1 /* xnu.c - load xnu kernel. Thanks to Florian Idelberger for all the
2 time he spent testing this
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>
24 #include <grub/cpu/xnu.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>
35 #include <grub/i18n.h>
37 #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
38 #include <grub/autoefi.h>
41 struct grub_xnu_devtree_key
*grub_xnu_devtree_root
= 0;
42 static int driverspackagenum
= 0;
43 static int driversnum
= 0;
44 int grub_xnu_is_64bit
= 0;
46 grub_addr_t grub_xnu_heap_target_start
= 0;
47 grub_size_t grub_xnu_heap_size
= 0;
48 struct grub_relocator
*grub_xnu_relocator
;
51 grub_xnu_register_memory (char *prefix
, int *suffix
,
52 grub_addr_t addr
, grub_size_t size
);
54 grub_xnu_heap_malloc (int size
, void **src
, grub_addr_t
*target
)
57 grub_relocator_chunk_t ch
;
59 err
= grub_relocator_alloc_chunk_addr (grub_xnu_relocator
, &ch
,
60 grub_xnu_heap_target_start
61 + grub_xnu_heap_size
, size
);
65 *src
= get_virtual_current_address (ch
);
66 *target
= grub_xnu_heap_target_start
+ grub_xnu_heap_size
;
67 grub_xnu_heap_size
+= size
;
68 grub_dprintf ("xnu", "val=%p\n", *src
);
72 /* Make sure next block of the heap will be aligned.
73 Please notice: aligned are pointers AFTER relocation
74 and not the current ones. */
76 grub_xnu_align_heap (int align
)
79 = ALIGN_UP (grub_xnu_heap_target_start
+ grub_xnu_heap_size
, align
)
80 - grub_xnu_heap_target_start
;
84 /* Free subtree pointed by CUR. */
86 grub_xnu_free_devtree (struct grub_xnu_devtree_key
*cur
)
88 struct grub_xnu_devtree_key
*d
;
91 grub_free (cur
->name
);
92 if (cur
->datasize
== -1)
93 grub_xnu_free_devtree (cur
->first_child
);
95 grub_free (cur
->data
);
102 /* Compute the size of device tree in xnu format. */
104 grub_xnu_writetree_get_size (struct grub_xnu_devtree_key
*start
, char *name
)
107 struct grub_xnu_devtree_key
*cur
;
110 ret
= 2 * sizeof (grub_uint32_t
);
113 ret
+= 32 + sizeof (grub_uint32_t
)
114 + grub_strlen (name
) + 4
115 - (grub_strlen (name
) % 4);
117 for (cur
= start
; cur
; cur
= cur
->next
)
118 if (cur
->datasize
!= -1)
122 align_overhead
= 4 - (cur
->datasize
% 4);
123 if (align_overhead
== 4)
125 ret
+= 32 + sizeof (grub_uint32_t
) + cur
->datasize
+ align_overhead
;
128 ret
+= grub_xnu_writetree_get_size (cur
->first_child
, cur
->name
);
132 /* Write devtree in XNU format at curptr assuming the head is named NAME.*/
134 grub_xnu_writetree_toheap_real (void *curptr
,
135 struct grub_xnu_devtree_key
*start
, char *name
)
137 struct grub_xnu_devtree_key
*cur
;
138 int nkeys
= 0, nvals
= 0;
139 for (cur
= start
; cur
; cur
= cur
->next
)
141 if (cur
->datasize
== -1)
149 *((grub_uint32_t
*) curptr
) = nvals
;
150 curptr
= ((grub_uint32_t
*) curptr
) + 1;
151 *((grub_uint32_t
*) curptr
) = nkeys
;
152 curptr
= ((grub_uint32_t
*) curptr
) + 1;
154 /* First comes "name" value. */
155 grub_memset (curptr
, 0, 32);
156 grub_memcpy (curptr
, "name", 4);
157 curptr
= ((grub_uint8_t
*) curptr
) + 32;
158 *((grub_uint32_t
*)curptr
) = grub_strlen (name
) + 1;
159 curptr
= ((grub_uint32_t
*) curptr
) + 1;
160 grub_memcpy (curptr
, name
, grub_strlen (name
));
161 curptr
= ((grub_uint8_t
*) curptr
) + grub_strlen (name
);
162 grub_memset (curptr
, 0, 4 - (grub_strlen (name
) % 4));
163 curptr
= ((grub_uint8_t
*) curptr
) + (4 - (grub_strlen (name
) % 4));
165 /* Then the other values. */
166 for (cur
= start
; cur
; cur
= cur
->next
)
167 if (cur
->datasize
!= -1)
171 align_overhead
= 4 - (cur
->datasize
% 4);
172 if (align_overhead
== 4)
174 grub_memset (curptr
, 0, 32);
175 grub_strncpy (curptr
, cur
->name
, 31);
176 curptr
= ((grub_uint8_t
*) curptr
) + 32;
177 *((grub_uint32_t
*) curptr
) = cur
->datasize
;
178 curptr
= ((grub_uint32_t
*) curptr
) + 1;
179 grub_memcpy (curptr
, cur
->data
, cur
->datasize
);
180 curptr
= ((grub_uint8_t
*) curptr
) + cur
->datasize
;
181 grub_memset (curptr
, 0, align_overhead
);
182 curptr
= ((grub_uint8_t
*) curptr
) + align_overhead
;
185 /* And then the keys. Recursively use this function. */
186 for (cur
= start
; cur
; cur
= cur
->next
)
187 if (cur
->datasize
== -1)
188 if (!(curptr
= grub_xnu_writetree_toheap_real (curptr
,
196 grub_xnu_writetree_toheap (grub_addr_t
*target
, grub_size_t
*size
)
198 struct grub_xnu_devtree_key
*chosen
;
199 struct grub_xnu_devtree_key
*memorymap
;
200 struct grub_xnu_devtree_key
*driverkey
;
201 struct grub_xnu_extdesc
*extdesc
;
205 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
209 /* Device tree itself is in the memory map of device tree. */
210 /* Create a dummy value in memory-map. */
211 chosen
= grub_xnu_create_key (&grub_xnu_devtree_root
, "chosen");
214 memorymap
= grub_xnu_create_key (&(chosen
->first_child
), "memory-map");
218 driverkey
= (struct grub_xnu_devtree_key
*) grub_malloc (sizeof (*driverkey
));
220 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't write device tree");
221 driverkey
->name
= grub_strdup ("DeviceTree");
222 if (! driverkey
->name
)
223 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't write device tree");
224 driverkey
->datasize
= sizeof (*extdesc
);
225 driverkey
->next
= memorymap
->first_child
;
226 memorymap
->first_child
= driverkey
;
227 driverkey
->data
= extdesc
228 = (struct grub_xnu_extdesc
*) grub_malloc (sizeof (*extdesc
));
229 if (! driverkey
->data
)
230 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't write device tree");
232 /* Allocate the space based on the size with dummy value. */
233 *size
= grub_xnu_writetree_get_size (grub_xnu_devtree_root
, "/");
234 err
= grub_xnu_heap_malloc (ALIGN_UP (*size
+ 1, GRUB_XNU_PAGESIZE
),
239 /* Put real data in the dummy. */
240 extdesc
->addr
= *target
;
241 extdesc
->size
= (grub_uint32_t
) *size
;
243 /* Write the tree to heap. */
244 grub_xnu_writetree_toheap_real (src
, grub_xnu_devtree_root
, "/");
245 return GRUB_ERR_NONE
;
248 /* Find a key or value in parent key. */
249 struct grub_xnu_devtree_key
*
250 grub_xnu_find_key (struct grub_xnu_devtree_key
*parent
, char *name
)
252 struct grub_xnu_devtree_key
*cur
;
253 for (cur
= parent
; cur
; cur
= cur
->next
)
254 if (grub_strcmp (cur
->name
, name
) == 0)
259 struct grub_xnu_devtree_key
*
260 grub_xnu_create_key (struct grub_xnu_devtree_key
**parent
, char *name
)
262 struct grub_xnu_devtree_key
*ret
;
263 ret
= grub_xnu_find_key (*parent
, name
);
266 ret
= (struct grub_xnu_devtree_key
*) grub_zalloc (sizeof (*ret
));
269 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't create key %s", name
);
272 ret
->name
= grub_strdup (name
);
276 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't create key %s", name
);
285 struct grub_xnu_devtree_key
*
286 grub_xnu_create_value (struct grub_xnu_devtree_key
**parent
, char *name
)
288 struct grub_xnu_devtree_key
*ret
;
289 ret
= grub_xnu_find_key (*parent
, name
);
292 if (ret
->datasize
== -1)
293 grub_xnu_free_devtree (ret
->first_child
);
294 else if (ret
->datasize
)
295 grub_free (ret
->data
);
300 ret
= (struct grub_xnu_devtree_key
*) grub_zalloc (sizeof (*ret
));
303 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't create value %s", name
);
306 ret
->name
= grub_strdup (name
);
310 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't create value %s", name
);
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. */
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;
334 return GRUB_ERR_NONE
;
338 grub_cmd_xnu_kernel (grub_command_t cmd
__attribute__ ((unused
)),
339 int argc
, char *args
[])
343 grub_uint32_t startcode
, endcode
;
347 grub_addr_t loadaddr_target
;
350 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
354 macho
= grub_macho_open (args
[0]);
357 if (! grub_macho_contains_macho32 (macho
))
359 grub_macho_close (macho
);
360 return grub_error (GRUB_ERR_BAD_OS
,
361 "kernel doesn't contain suitable 32-bit architecture");
364 err
= grub_macho_size32 (macho
, &startcode
, &endcode
, GRUB_MACHO_NOBSS
);
367 grub_macho_close (macho
);
372 grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
373 (unsigned long) endcode
, (unsigned long) startcode
);
375 grub_xnu_relocator
= grub_relocator_new ();
376 if (!grub_xnu_relocator
)
378 grub_xnu_heap_target_start
= startcode
;
379 err
= grub_xnu_heap_malloc (endcode
- startcode
, &loadaddr
,
384 grub_macho_close (macho
);
390 err
= grub_macho_load32 (macho
, (char *) loadaddr
- startcode
,
394 grub_macho_close (macho
);
399 grub_xnu_entry_point
= grub_macho_get_entry_point32 (macho
);
400 if (! grub_xnu_entry_point
)
402 grub_macho_close (macho
);
404 return grub_error (GRUB_ERR_BAD_OS
, "couldn't find entry point");
407 grub_macho_close (macho
);
409 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
416 /* Copy parameters to kernel command line. */
417 ptr
= grub_xnu_cmdline
;
418 for (i
= 1; i
< argc
; i
++)
420 if (ptr
+ grub_strlen (args
[i
]) + 1
421 >= grub_xnu_cmdline
+ sizeof (grub_xnu_cmdline
))
423 grub_memcpy (ptr
, args
[i
], grub_strlen (args
[i
]));
424 ptr
+= grub_strlen (args
[i
]);
429 /* Replace last space by '\0'. */
430 if (ptr
!= grub_xnu_cmdline
)
433 #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
434 err
= grub_efiemu_autocore ();
439 grub_loader_set (grub_xnu_boot
, grub_xnu_unload
, 0);
442 grub_xnu_is_64bit
= 0;
448 grub_cmd_xnu_kernel64 (grub_command_t cmd
__attribute__ ((unused
)),
449 int argc
, char *args
[])
453 grub_uint64_t startcode
, endcode
;
457 grub_addr_t loadaddr_target
;
460 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
464 macho
= grub_macho_open (args
[0]);
467 if (! grub_macho_contains_macho64 (macho
))
469 grub_macho_close (macho
);
470 return grub_error (GRUB_ERR_BAD_OS
,
471 "kernel doesn't contain suitable 64-bit architecture");
474 err
= grub_macho_size64 (macho
, &startcode
, &endcode
, GRUB_MACHO_NOBSS
);
477 grub_macho_close (macho
);
482 startcode
&= 0x0fffffff;
483 endcode
&= 0x0fffffff;
485 grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
486 (unsigned long) endcode
, (unsigned long) startcode
);
488 grub_xnu_relocator
= grub_relocator_new ();
489 if (!grub_xnu_relocator
)
491 grub_xnu_heap_target_start
= startcode
;
492 err
= grub_xnu_heap_malloc (endcode
- startcode
, &loadaddr
,
497 grub_macho_close (macho
);
503 err
= grub_macho_load64 (macho
, (char *) loadaddr
- startcode
,
507 grub_macho_close (macho
);
512 grub_xnu_entry_point
= grub_macho_get_entry_point64 (macho
) & 0x0fffffff;
513 if (! grub_xnu_entry_point
)
515 grub_macho_close (macho
);
517 return grub_error (GRUB_ERR_BAD_OS
, "couldn't find entry point");
520 grub_macho_close (macho
);
522 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
529 /* Copy parameters to kernel command line. */
530 ptr
= grub_xnu_cmdline
;
531 for (i
= 1; i
< argc
; i
++)
533 if (ptr
+ grub_strlen (args
[i
]) + 1
534 >= grub_xnu_cmdline
+ sizeof (grub_xnu_cmdline
))
536 grub_memcpy (ptr
, args
[i
], grub_strlen (args
[i
]));
537 ptr
+= grub_strlen (args
[i
]);
542 /* Replace last space by '\0'. */
543 if (ptr
!= grub_xnu_cmdline
)
546 #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
547 err
= grub_efiemu_autocore ();
552 grub_loader_set (grub_xnu_boot
, grub_xnu_unload
, 0);
555 grub_xnu_is_64bit
= 1;
560 /* Register a memory in a memory map under name PREFIXSUFFIX
561 and increment SUFFIX. */
563 grub_xnu_register_memory (char *prefix
, int *suffix
,
564 grub_addr_t addr
, grub_size_t size
)
566 struct grub_xnu_devtree_key
*chosen
;
567 struct grub_xnu_devtree_key
*memorymap
;
568 struct grub_xnu_devtree_key
*driverkey
;
569 struct grub_xnu_extdesc
*extdesc
;
571 if (! grub_xnu_heap_size
)
572 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
574 chosen
= grub_xnu_create_key (&grub_xnu_devtree_root
, "chosen");
577 memorymap
= grub_xnu_create_key (&(chosen
->first_child
), "memory-map");
581 driverkey
= (struct grub_xnu_devtree_key
*) grub_malloc (sizeof (*driverkey
));
583 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't register memory");
586 driverkey
->name
= grub_xasprintf ("%s%d", prefix
, (*suffix
)++);
587 if (!driverkey
->name
)
588 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't register memory");
591 driverkey
->name
= grub_strdup (prefix
);
592 if (! driverkey
->name
)
593 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't register extension");
594 driverkey
->datasize
= sizeof (*extdesc
);
595 driverkey
->next
= memorymap
->first_child
;
596 memorymap
->first_child
= driverkey
;
597 driverkey
->data
= extdesc
598 = (struct grub_xnu_extdesc
*) grub_malloc (sizeof (*extdesc
));
599 if (! driverkey
->data
)
600 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't register extension");
601 extdesc
->addr
= addr
;
602 extdesc
->size
= (grub_uint32_t
) size
;
603 return GRUB_ERR_NONE
;
607 get_name_ptr (char *name
)
610 /* Skip Info.plist. */
611 p2
= grub_strrchr (p
, '/');
618 p2
= grub_strrchr (p
, '/');
623 if (grub_memcmp (p2
, "/Contents/", sizeof ("/Contents/") - 1) != 0)
628 p2
= grub_strrchr (p
, '/');
636 grub_xnu_load_driver (char *infoplistname
, grub_file_t binaryfile
)
640 grub_file_t infoplist
;
641 struct grub_xnu_extheader
*exthead
;
642 int neededspace
= sizeof (*exthead
);
645 grub_addr_t buf_target
;
646 grub_size_t infoplistsize
= 0, machosize
= 0;
647 char *name
, *nameend
;
650 name
= get_name_ptr (infoplistname
);
651 nameend
= grub_strchr (name
, '/');
654 namelen
= nameend
- name
;
656 namelen
= grub_strlen (name
);
658 neededspace
+= namelen
+ 1;
660 if (! grub_xnu_heap_size
)
661 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
663 /* Compute the needed space. */
666 macho
= grub_macho_file (binaryfile
);
667 if (! macho
|| ! grub_macho_contains_macho32 (macho
))
670 grub_macho_close (macho
);
671 return grub_error (GRUB_ERR_BAD_OS
,
672 "extension doesn't contain suitable architecture");
674 if (grub_xnu_is_64bit
)
675 machosize
= grub_macho_filesize64 (macho
);
677 machosize
= grub_macho_filesize32 (macho
);
678 neededspace
+= machosize
;
684 infoplist
= grub_file_open (infoplistname
);
687 grub_errno
= GRUB_ERR_NONE
;
690 infoplistsize
= grub_file_size (infoplist
);
691 neededspace
+= infoplistsize
+ 1;
696 /* Allocate the space. */
697 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
700 err
= grub_xnu_heap_malloc (neededspace
, &buf0
, &buf_target
);
705 exthead
= (struct grub_xnu_extheader
*) buf
;
706 grub_memset (exthead
, 0, sizeof (*exthead
));
707 buf
+= sizeof (*exthead
);
709 /* Load the binary. */
712 exthead
->binaryaddr
= buf_target
+ (buf
- (grub_uint8_t
*) buf0
);
713 exthead
->binarysize
= machosize
;
714 if (grub_xnu_is_64bit
)
715 err
= grub_macho_readfile64 (macho
, buf
);
717 err
= grub_macho_readfile32 (macho
, buf
);
720 grub_macho_close (macho
);
723 grub_macho_close (macho
);
726 grub_errno
= GRUB_ERR_NONE
;
728 /* Load the plist. */
731 exthead
->infoplistaddr
= buf_target
+ (buf
- (grub_uint8_t
*) buf0
);
732 exthead
->infoplistsize
= infoplistsize
+ 1;
733 if (grub_file_read (infoplist
, buf
, infoplistsize
)
734 != (grub_ssize_t
) (infoplistsize
))
736 grub_file_close (infoplist
);
738 return grub_error (GRUB_ERR_BAD_OS
, "couldn't read file %s: ",
741 grub_file_close (infoplist
);
742 buf
[infoplistsize
] = 0;
743 buf
+= infoplistsize
+ 1;
745 grub_errno
= GRUB_ERR_NONE
;
747 exthead
->nameaddr
= (buf
- (grub_uint8_t
*) buf0
) + buf_target
;
748 exthead
->namesize
= namelen
+ 1;
749 grub_memcpy (buf
, name
, namelen
);
753 /* Announce to kernel */
754 return grub_xnu_register_memory ("Driver-", &driversnum
, buf_target
,
760 grub_cmd_xnu_mkext (grub_command_t cmd
__attribute__ ((unused
)),
761 int argc
, char *args
[])
765 grub_addr_t loadto_target
;
767 grub_off_t readoff
= 0;
768 grub_ssize_t readlen
= -1;
769 struct grub_macho_fat_header head
;
770 struct grub_macho_fat_arch
*archs
;
774 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
776 if (! grub_xnu_heap_size
)
777 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
779 file
= grub_file_open (args
[0]);
781 return grub_error (GRUB_ERR_FILE_NOT_FOUND
,
782 "couldn't load driver package");
784 /* Sometimes caches are fat binary. Errgh. */
785 if (grub_file_read (file
, &head
, sizeof (head
))
786 != (grub_ssize_t
) (sizeof (head
)))
788 /* I don't know the internal structure of package but
789 can hardly imagine a valid package shorter than 20 bytes. */
790 grub_file_close (file
);
792 return grub_error (GRUB_ERR_BAD_OS
, "couldn't read file %s", args
[0]);
795 /* Find the corresponding architecture. */
796 if (grub_be_to_cpu32 (head
.magic
) == GRUB_MACHO_FAT_MAGIC
)
798 narchs
= grub_be_to_cpu32 (head
.nfat_arch
);
799 archs
= grub_malloc (sizeof (struct grub_macho_fat_arch
) * narchs
);
802 grub_file_close (file
);
804 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
805 "couldn't read file %s", args
[0]);
808 if (grub_file_read (file
, archs
,
809 sizeof (struct grub_macho_fat_arch
) * narchs
)
810 != (grub_ssize_t
) sizeof(struct grub_macho_fat_arch
) * narchs
)
814 return grub_error (GRUB_ERR_READ_ERROR
, "cannot read fat header");
816 for (i
= 0; i
< narchs
; i
++)
818 if (!grub_xnu_is_64bit
&& GRUB_MACHO_CPUTYPE_IS_HOST32
819 (grub_be_to_cpu32 (archs
[i
].cputype
)))
821 readoff
= grub_be_to_cpu32 (archs
[i
].offset
);
822 readlen
= grub_be_to_cpu32 (archs
[i
].size
);
824 if (grub_xnu_is_64bit
&& GRUB_MACHO_CPUTYPE_IS_HOST64
825 (grub_be_to_cpu32 (archs
[i
].cputype
)))
827 readoff
= grub_be_to_cpu32 (archs
[i
].offset
);
828 readlen
= grub_be_to_cpu32 (archs
[i
].size
);
835 /* It's a flat file. Some sane people still exist. */
837 readlen
= grub_file_size (file
);
842 grub_file_close (file
);
843 return grub_error (GRUB_ERR_BAD_OS
, "no suitable architecture is found");
846 /* Allocate space. */
847 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
850 grub_file_close (file
);
854 err
= grub_xnu_heap_malloc (readlen
, &loadto
, &loadto_target
);
857 grub_file_close (file
);
862 grub_file_seek (file
, readoff
);
863 if (grub_file_read (file
, loadto
, readlen
) != (grub_ssize_t
) (readlen
))
865 grub_file_close (file
);
867 return grub_error (GRUB_ERR_BAD_OS
, "couldn't read file %s", args
[0]);
869 grub_file_close (file
);
871 /* Pass it to kernel. */
872 return grub_xnu_register_memory ("DriversPackage-", &driverspackagenum
,
873 loadto_target
, readlen
);
877 grub_cmd_xnu_ramdisk (grub_command_t cmd
__attribute__ ((unused
)),
878 int argc
, char *args
[])
882 grub_addr_t loadto_target
;
887 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
889 if (! grub_xnu_heap_size
)
890 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
892 file
= grub_file_open (args
[0]);
894 return grub_error (GRUB_ERR_FILE_NOT_FOUND
,
895 "couldn't load ramdisk");
897 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
901 size
= grub_file_size (file
);
903 err
= grub_xnu_heap_malloc (size
, &loadto
, &loadto_target
);
906 if (grub_file_read (file
, loadto
, size
)
907 != (grub_ssize_t
) (size
))
909 grub_file_close (file
);
911 return grub_error (GRUB_ERR_BAD_OS
, "couldn't read file %s", args
[0]);
913 return grub_xnu_register_memory ("RAMDisk", 0, loadto_target
, size
);
916 /* Returns true if the kext should be loaded according to plist
917 and osbundlereq. Also fill BINNAME. */
919 grub_xnu_check_os_bundle_required (char *plistname
, char *osbundlereq
,
923 char *buf
= 0, *tagstart
= 0, *ptr1
= 0, *keyptr
= 0;
924 char *stringptr
= 0, *ptr2
= 0;
928 int osbundlekeyfound
= 0, binnamekeyfound
= 0;
932 file
= grub_file_open (plistname
);
935 grub_file_close (file
);
937 grub_error (GRUB_ERR_BAD_OS
, "couldn't read file %s", plistname
);
941 size
= grub_file_size (file
);
942 buf
= grub_malloc (size
);
945 grub_file_close (file
);
947 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "couldn't read file %s", plistname
);
950 if (grub_file_read (file
, buf
, size
) != (grub_ssize_t
) (size
))
952 grub_file_close (file
);
954 grub_error (GRUB_ERR_BAD_OS
, "couldn't read file %s", plistname
);
957 grub_file_close (file
);
959 /* Set the return value for the case when no OSBundleRequired tag is found. */
961 ret
= grub_strword (osbundlereq
, "all") || grub_strword (osbundlereq
, "-");
965 /* Parse plist. It's quite dirty and inextensible but does its job. */
966 for (ptr1
= buf
; ptr1
< buf
+ size
; ptr1
++)
972 if (keyptr
&& depth
== 4
973 && grub_strcmp (keyptr
, "OSBundleRequired") == 0)
974 osbundlekeyfound
= 1;
975 if (keyptr
&& depth
== 4 &&
976 grub_strcmp (keyptr
, "CFBundleExecutable") == 0)
978 if (stringptr
&& osbundlekeyfound
&& osbundlereq
&& depth
== 4)
980 for (ptr2
= stringptr
; *ptr2
; ptr2
++)
981 *ptr2
= grub_tolower (*ptr2
);
982 ret
= grub_strword (osbundlereq
, stringptr
)
983 || grub_strword (osbundlereq
, "all");
985 if (stringptr
&& binnamekeyfound
&& binname
&& depth
== 4)
988 grub_free (*binname
);
989 *binname
= grub_strdup (stringptr
);
1000 grub_error (GRUB_ERR_BAD_OS
, "can't parse %s", plistname
);
1004 if (tagstart
[1] == '?' || ptr1
[-1] == '/')
1006 osbundlekeyfound
= 0;
1010 if (depth
== 3 && grub_strcmp (tagstart
+ 1, "key") == 0)
1012 if (depth
== 3 && grub_strcmp (tagstart
+ 1, "string") == 0)
1013 stringptr
= ptr1
+ 1;
1014 else if (grub_strcmp (tagstart
+ 1, "/key") != 0)
1016 osbundlekeyfound
= 0;
1017 binnamekeyfound
= 0;
1021 if (tagstart
[1] == '/')
1032 /* Load all loadable kexts placed under DIRNAME and matching OSBUNDLEREQUIRED */
1034 grub_xnu_scan_dir_for_kexts (char *dirname
, char *osbundlerequired
,
1042 auto int load_hook (const char *filename
,
1043 const struct grub_dirhook_info
*info
);
1044 int load_hook (const char *filename
, const struct grub_dirhook_info
*info
)
1049 if (filename
[0] == '.')
1052 if (grub_strlen (filename
) < 5 ||
1053 grub_memcmp (filename
+ grub_strlen (filename
) - 5, ".kext", 5) != 0)
1057 = grub_malloc (grub_strlen (dirname
) + grub_strlen (filename
) + 2);
1059 /* It's a .kext. Try to load it. */
1062 grub_strcpy (newdirname
, dirname
);
1063 newdirname
[grub_strlen (newdirname
) + 1] = 0;
1064 newdirname
[grub_strlen (newdirname
)] = '/';
1065 grub_strcpy (newdirname
+ grub_strlen (newdirname
), filename
);
1066 grub_xnu_load_kext_from_dir (newdirname
, osbundlerequired
,
1068 if (grub_errno
== GRUB_ERR_BAD_OS
)
1069 grub_errno
= GRUB_ERR_NONE
;
1070 grub_free (newdirname
);
1075 if (! grub_xnu_heap_size
)
1076 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
1078 device_name
= grub_file_get_device_name (dirname
);
1079 dev
= grub_device_open (device_name
);
1082 fs
= grub_fs_probe (dev
);
1083 path
= grub_strchr (dirname
, ')');
1090 (fs
->dir
) (dev
, path
, load_hook
);
1091 grub_device_close (dev
);
1093 grub_free (device_name
);
1095 return GRUB_ERR_NONE
;
1098 /* Load extension DIRNAME. (extensions are directories in xnu) */
1100 grub_xnu_load_kext_from_dir (char *dirname
, char *osbundlerequired
,
1104 char *plistname
= 0;
1112 grub_file_t binfile
;
1114 auto int load_hook (const char *filename
,
1115 const struct grub_dirhook_info
*info
);
1117 int load_hook (const char *filename
, const struct grub_dirhook_info
*info
)
1119 if (grub_strlen (filename
) > 15)
1121 grub_strcpy (newdirname
+ grub_strlen (dirname
) + 1, filename
);
1123 /* If the kext contains directory "Contents" all real stuff is in
1125 if (info
->dir
&& grub_strcasecmp (filename
, "Contents") == 0)
1126 grub_xnu_load_kext_from_dir (newdirname
, osbundlerequired
,
1129 /* Directory "Plugins" contains nested kexts. */
1130 if (info
->dir
&& grub_strcasecmp (filename
, "Plugins") == 0)
1131 grub_xnu_scan_dir_for_kexts (newdirname
, osbundlerequired
,
1134 /* Directory "MacOS" contains executable, otherwise executable is
1136 if (info
->dir
&& grub_strcasecmp (filename
, "MacOS") == 0)
1139 /* Info.plist is the file which governs our future actions. */
1140 if (! info
->dir
&& grub_strcasecmp (filename
, "Info.plist") == 0
1142 plistname
= grub_strdup (newdirname
);
1146 newdirname
= grub_malloc (grub_strlen (dirname
) + 20);
1148 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "couldn't allocate buffer");
1149 grub_strcpy (newdirname
, dirname
);
1150 newdirname
[grub_strlen (dirname
)] = '/';
1151 newdirname
[grub_strlen (dirname
) + 1] = 0;
1152 device_name
= grub_file_get_device_name (dirname
);
1153 dev
= grub_device_open (device_name
);
1156 fs
= grub_fs_probe (dev
);
1157 path
= grub_strchr (dirname
, ')');
1163 newpath
= grub_strchr (newdirname
, ')');
1165 newpath
= newdirname
;
1169 /* Look at the directory. */
1171 (fs
->dir
) (dev
, path
, load_hook
);
1173 if (plistname
&& grub_xnu_check_os_bundle_required
1174 (plistname
, osbundlerequired
, &binsuffix
))
1178 /* Open the binary. */
1179 char *binname
= grub_malloc (grub_strlen (dirname
)
1180 + grub_strlen (binsuffix
)
1181 + sizeof ("/MacOS/"));
1182 grub_strcpy (binname
, dirname
);
1184 grub_strcpy (binname
+ grub_strlen (binname
), "/MacOS/");
1186 grub_strcpy (binname
+ grub_strlen (binname
), "/");
1187 grub_strcpy (binname
+ grub_strlen (binname
), binsuffix
);
1188 grub_dprintf ("xnu", "%s:%s\n", plistname
, binname
);
1189 binfile
= grub_file_open (binname
);
1191 grub_errno
= GRUB_ERR_NONE
;
1193 /* Load the extension. */
1194 grub_xnu_load_driver (plistname
, binfile
);
1195 grub_free (binname
);
1196 grub_free (binsuffix
);
1200 grub_dprintf ("xnu", "%s:0\n", plistname
);
1201 grub_xnu_load_driver (plistname
, 0);
1204 grub_free (plistname
);
1205 grub_device_close (dev
);
1207 grub_free (device_name
);
1209 return GRUB_ERR_NONE
;
1213 static int locked
=0;
1214 static grub_dl_t my_mod
;
1216 /* Load the kext. */
1218 grub_cmd_xnu_kext (grub_command_t cmd
__attribute__ ((unused
)),
1219 int argc
, char *args
[])
1221 grub_file_t binfile
= 0;
1223 if (! grub_xnu_heap_size
)
1224 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
1228 /* User explicitly specified plist and binary. */
1229 if (grub_strcmp (args
[1], "-") != 0)
1231 binfile
= grub_file_open (args
[1]);
1234 grub_error (GRUB_ERR_BAD_OS
, "can't open file");
1235 return GRUB_ERR_NONE
;
1238 return grub_xnu_load_driver (grub_strcmp (args
[0], "-") ? args
[0] : 0,
1242 /* load kext normally. */
1244 return grub_xnu_load_kext_from_dir (args
[0], 0, 10);
1246 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
1249 /* Load a directory containing kexts. */
1251 grub_cmd_xnu_kextdir (grub_command_t cmd
__attribute__ ((unused
)),
1252 int argc
, char *args
[])
1254 if (argc
!= 1 && argc
!= 2)
1255 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "directory name required");
1257 if (! grub_xnu_heap_size
)
1258 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
1261 return grub_xnu_scan_dir_for_kexts (args
[0],
1262 "console,root,local-root,network-root",
1266 char *osbundlerequired
= grub_strdup (args
[1]), *ptr
;
1268 if (! osbundlerequired
)
1269 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
1270 "couldn't allocate string temporary space");
1271 for (ptr
= osbundlerequired
; *ptr
; ptr
++)
1272 *ptr
= grub_tolower (*ptr
);
1273 err
= grub_xnu_scan_dir_for_kexts (args
[0], osbundlerequired
, 10);
1274 grub_free (osbundlerequired
);
1282 if (c
>= '0' && c
<= '9')
1284 if (c
>= 'a' && c
<= 'z')
1285 return c
- 'a' + 10;
1286 if (c
>= 'A' && c
<= 'Z')
1287 return c
- 'A' + 10;
1292 unescape (char *name
, char *curdot
, char *nextdot
, int *len
)
1296 for (ptr
= curdot
; ptr
< nextdot
;)
1297 if (ptr
+ 2 < nextdot
&& *ptr
== '%')
1299 *dptr
= (hextoval (ptr
[1]) << 4) | (hextoval (ptr
[2]));
1313 grub_xnu_fill_devicetree (void)
1315 auto int iterate_env (struct grub_env_var
*var
);
1316 int iterate_env (struct grub_env_var
*var
)
1318 char *nextdot
= 0, *curdot
;
1319 struct grub_xnu_devtree_key
**curkey
= &grub_xnu_devtree_root
;
1320 struct grub_xnu_devtree_key
*curvalue
;
1321 char *name
= 0, *data
;
1324 if (grub_memcmp (var
->name
, "XNU.DeviceTree.",
1325 sizeof ("XNU.DeviceTree.") - 1) != 0)
1328 curdot
= var
->name
+ sizeof ("XNU.DeviceTree.") - 1;
1329 nextdot
= grub_strchr (curdot
, '.');
1334 name
= grub_realloc (name
, nextdot
- curdot
+ 1);
1339 unescape (name
, curdot
, nextdot
, &len
);
1342 curkey
= &(grub_xnu_create_key (curkey
, name
)->first_child
);
1345 nextdot
= grub_strchr (nextdot
, '.');
1350 nextdot
= curdot
+ grub_strlen (curdot
) + 1;
1352 name
= grub_realloc (name
, nextdot
- curdot
+ 1);
1357 unescape (name
, curdot
, nextdot
, &len
);
1360 curvalue
= grub_xnu_create_value (curkey
, name
);
1363 data
= grub_malloc (grub_strlen (var
->value
) + 1);
1367 unescape (data
, var
->value
, var
->value
+ grub_strlen (var
->value
),
1369 curvalue
->datasize
= len
;
1370 curvalue
->data
= data
;
1375 grub_env_iterate (iterate_env
);
1380 struct grub_video_bitmap
*grub_xnu_bitmap
= 0;
1381 grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode
;
1383 /* Option array indices. */
1384 #define XNU_SPLASH_CMD_ARGINDEX_MODE 0
1386 static const struct grub_arg_option xnu_splash_cmd_options
[] =
1388 {"mode", 'm', 0, "Background image mode.", "stretch|normal",
1394 grub_cmd_xnu_splash (grub_extcmd_context_t ctxt
,
1395 int argc
, char *args
[])
1399 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
1401 if (! grub_xnu_heap_size
)
1402 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
1404 if (ctxt
->state
[XNU_SPLASH_CMD_ARGINDEX_MODE
].set
&&
1405 grub_strcmp (ctxt
->state
[XNU_SPLASH_CMD_ARGINDEX_MODE
].arg
,
1407 grub_xnu_bitmap_mode
= GRUB_XNU_BITMAP_STRETCH
;
1409 grub_xnu_bitmap_mode
= GRUB_XNU_BITMAP_CENTER
;
1411 err
= grub_video_bitmap_load (&grub_xnu_bitmap
, args
[0]);
1413 grub_xnu_bitmap
= 0;
1419 #ifndef GRUB_MACHINE_EMU
1421 grub_cmd_xnu_resume (grub_command_t cmd
__attribute__ ((unused
)),
1422 int argc
, char *args
[])
1425 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
1427 return grub_xnu_resume (args
[0]);
1432 grub_xnu_lock (void)
1435 grub_dl_ref (my_mod
);
1440 grub_xnu_unlock (void)
1443 grub_dl_unref (my_mod
);
1447 static grub_command_t cmd_kernel64
, cmd_kernel
, cmd_mkext
, cmd_kext
;
1448 static grub_command_t cmd_kextdir
, cmd_ramdisk
, cmd_resume
;
1449 static grub_extcmd_t cmd_splash
;
1453 cmd_kernel
= grub_register_command ("xnu_kernel", grub_cmd_xnu_kernel
, 0,
1454 N_("Load XNU image."));
1455 cmd_kernel64
= grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64
,
1456 0, N_("Load 64-bit XNU image."));
1457 cmd_mkext
= grub_register_command ("xnu_mkext", grub_cmd_xnu_mkext
, 0,
1458 N_("Load XNU extension package."));
1459 cmd_kext
= grub_register_command ("xnu_kext", grub_cmd_xnu_kext
, 0,
1460 N_("Load XNU extension."));
1461 cmd_kextdir
= grub_register_command ("xnu_kextdir", grub_cmd_xnu_kextdir
,
1462 N_("DIRECTORY [OSBundleRequired]"),
1463 N_("Load XNU extension directory."));
1464 cmd_ramdisk
= grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk
, 0,
1465 "Load XNU ramdisk. "
1466 "It will be seen as md0.");
1467 cmd_splash
= grub_register_extcmd ("xnu_splash",
1468 grub_cmd_xnu_splash
, 0, 0,
1469 N_("Load a splash image for XNU."),
1470 xnu_splash_cmd_options
);
1472 #ifndef GRUB_MACHINE_EMU
1473 cmd_resume
= grub_register_command ("xnu_resume", grub_cmd_xnu_resume
,
1474 0, N_("Load XNU hibernate image."));
1477 grub_cpu_xnu_init ();
1484 #ifndef GRUB_MACHINE_EMU
1485 grub_unregister_command (cmd_resume
);
1487 grub_unregister_command (cmd_mkext
);
1488 grub_unregister_command (cmd_kext
);
1489 grub_unregister_command (cmd_kextdir
);
1490 grub_unregister_command (cmd_ramdisk
);
1491 grub_unregister_command (cmd_kernel
);
1492 grub_unregister_extcmd (cmd_splash
);
1493 grub_unregister_command (cmd_kernel64
);
1495 grub_cpu_xnu_fini ();