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/gzio.h>
32 #include <grub/command.h>
33 #include <grub/misc.h>
35 struct grub_xnu_devtree_key
*grub_xnu_devtree_root
= 0;
36 static int driverspackagenum
= 0;
37 static int driversnum
= 0;
39 /* Allocate heap by 32MB-blocks. */
40 #define GRUB_XNU_HEAP_ALLOC_BLOCK 0x2000000
43 grub_xnu_register_memory (char *prefix
, int *suffix
,
44 void *addr
, grub_size_t size
);
46 grub_xnu_heap_malloc (int size
)
51 /* This way booting is faster but less reliable.
52 Once we have advanced mm second way will be as fast as this one. */
53 val
= grub_xnu_heap_start
= (char *) 0x100000;
55 int oldblknum
, newblknum
;
57 /* The page after the heap is used for stack. Ensure it's usable. */
58 if (grub_xnu_heap_size
)
59 oldblknum
= (grub_xnu_heap_size
+ GRUB_XNU_PAGESIZE
60 + GRUB_XNU_HEAP_ALLOC_BLOCK
- 1) / GRUB_XNU_HEAP_ALLOC_BLOCK
;
63 newblknum
= (grub_xnu_heap_size
+ size
+ GRUB_XNU_PAGESIZE
64 + GRUB_XNU_HEAP_ALLOC_BLOCK
- 1) / GRUB_XNU_HEAP_ALLOC_BLOCK
;
65 if (oldblknum
!= newblknum
)
66 /* FIXME: instruct realloc to allocate at 1MB if possible once
67 advanced mm is ready. */
68 val
= grub_realloc (grub_xnu_heap_start
,
69 newblknum
* GRUB_XNU_HEAP_ALLOC_BLOCK
);
71 val
= grub_xnu_heap_start
;
74 grub_error (GRUB_ERR_OUT_OF_MEMORY
,
75 "not enough space on xnu memory heap");
78 grub_xnu_heap_start
= val
;
81 val
= (char *) grub_xnu_heap_start
+ grub_xnu_heap_size
;
82 grub_xnu_heap_size
+= size
;
83 grub_dprintf ("xnu", "val=%p\n", val
);
87 /* Make sure next block of the heap will be aligned.
88 Please notice: aligned are pointers AFTER relocation
89 and not the current ones. */
91 grub_xnu_align_heap (int align
)
93 int align_overhead
= align
- grub_xnu_heap_size
% align
;
94 if (align_overhead
== align
)
96 if (! grub_xnu_heap_malloc (align_overhead
))
101 /* Free subtree pointed by CUR. */
103 grub_xnu_free_devtree (struct grub_xnu_devtree_key
*cur
)
105 struct grub_xnu_devtree_key
*d
;
108 grub_free (cur
->name
);
109 if (cur
->datasize
== -1)
110 grub_xnu_free_devtree (cur
->first_child
);
112 grub_free (cur
->data
);
119 /* Compute the size of device tree in xnu format. */
121 grub_xnu_writetree_get_size (struct grub_xnu_devtree_key
*start
, char *name
)
124 struct grub_xnu_devtree_key
*cur
;
127 ret
= 2 * sizeof (grub_uint32_t
);
130 ret
+= 32 + sizeof (grub_uint32_t
)
131 + grub_strlen (name
) + 4
132 - (grub_strlen (name
) % 4);
134 for (cur
= start
; cur
; cur
= cur
->next
)
135 if (cur
->datasize
!= -1)
139 align_overhead
= 4 - (cur
->datasize
% 4);
140 if (align_overhead
== 4)
142 ret
+= 32 + sizeof (grub_uint32_t
) + cur
->datasize
+ align_overhead
;
145 ret
+= grub_xnu_writetree_get_size (cur
->first_child
, cur
->name
);
149 /* Write devtree in XNU format at curptr assuming the head is named NAME.*/
151 grub_xnu_writetree_toheap_real (void *curptr
,
152 struct grub_xnu_devtree_key
*start
, char *name
)
154 struct grub_xnu_devtree_key
*cur
;
155 int nkeys
= 0, nvals
= 0;
156 for (cur
= start
; cur
; cur
= cur
->next
)
158 if (cur
->datasize
== -1)
166 *((grub_uint32_t
*) curptr
) = nvals
;
167 curptr
= ((grub_uint32_t
*) curptr
) + 1;
168 *((grub_uint32_t
*) curptr
) = nkeys
;
169 curptr
= ((grub_uint32_t
*) curptr
) + 1;
171 /* First comes "name" value. */
172 grub_memset (curptr
, 0, 32);
173 grub_memcpy (curptr
, "name", 4);
174 curptr
= ((grub_uint8_t
*) curptr
) + 32;
175 *((grub_uint32_t
*)curptr
) = grub_strlen (name
) + 1;
176 curptr
= ((grub_uint32_t
*) curptr
) + 1;
177 grub_memcpy (curptr
, name
, grub_strlen (name
));
178 curptr
= ((grub_uint8_t
*) curptr
) + grub_strlen (name
);
179 grub_memset (curptr
, 0, 4 - (grub_strlen (name
) % 4));
180 curptr
= ((grub_uint8_t
*) curptr
) + (4 - (grub_strlen (name
) % 4));
182 /* Then the other values. */
183 for (cur
= start
; cur
; cur
= cur
->next
)
184 if (cur
->datasize
!= -1)
188 align_overhead
= 4 - (cur
->datasize
% 4);
189 if (align_overhead
== 4)
191 grub_memset (curptr
, 0, 32);
192 grub_strncpy (curptr
, cur
->name
, 31);
193 curptr
= ((grub_uint8_t
*) curptr
) + 32;
194 *((grub_uint32_t
*) curptr
) = cur
->datasize
;
195 curptr
= ((grub_uint32_t
*) curptr
) + 1;
196 grub_memcpy (curptr
, cur
->data
, cur
->datasize
);
197 curptr
= ((grub_uint8_t
*) curptr
) + cur
->datasize
;
198 grub_memset (curptr
, 0, align_overhead
);
199 curptr
= ((grub_uint8_t
*) curptr
) + align_overhead
;
202 /* And then the keys. Recursively use this function. */
203 for (cur
= start
; cur
; cur
= cur
->next
)
204 if (cur
->datasize
== -1)
205 if (!(curptr
= grub_xnu_writetree_toheap_real (curptr
,
213 grub_xnu_writetree_toheap (void **start
, grub_size_t
*size
)
215 struct grub_xnu_devtree_key
*chosen
;
216 struct grub_xnu_devtree_key
*memorymap
;
217 struct grub_xnu_devtree_key
*driverkey
;
218 struct grub_xnu_extdesc
*extdesc
;
221 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
225 /* Device tree itself is in the memory map of device tree. */
226 /* Create a dummy value in memory-map. */
227 chosen
= grub_xnu_create_key (&grub_xnu_devtree_root
, "chosen");
230 memorymap
= grub_xnu_create_key (&(chosen
->first_child
), "memory-map");
234 driverkey
= (struct grub_xnu_devtree_key
*) grub_malloc (sizeof (*driverkey
));
236 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't write device tree");
237 driverkey
->name
= grub_strdup ("DeviceTree");
238 if (! driverkey
->name
)
239 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't write device tree");
240 driverkey
->datasize
= sizeof (*extdesc
);
241 driverkey
->next
= memorymap
->first_child
;
242 memorymap
->first_child
= driverkey
;
243 driverkey
->data
= extdesc
244 = (struct grub_xnu_extdesc
*) grub_malloc (sizeof (*extdesc
));
245 if (! driverkey
->data
)
246 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't write device tree");
248 /* Allocate the space based on the size with dummy value. */
249 *size
= grub_xnu_writetree_get_size (grub_xnu_devtree_root
, "/");
250 *start
= grub_xnu_heap_malloc (*size
+ GRUB_XNU_PAGESIZE
251 - *size
% GRUB_XNU_PAGESIZE
);
253 /* Put real data in the dummy. */
254 extdesc
->addr
= (char *) *start
- grub_xnu_heap_start
255 + grub_xnu_heap_will_be_at
;
256 extdesc
->size
= (grub_uint32_t
) *size
;
258 /* Write the tree to heap. */
259 grub_xnu_writetree_toheap_real (*start
, grub_xnu_devtree_root
, "/");
260 return GRUB_ERR_NONE
;
263 /* Find a key or value in parent key. */
264 struct grub_xnu_devtree_key
*
265 grub_xnu_find_key (struct grub_xnu_devtree_key
*parent
, char *name
)
267 struct grub_xnu_devtree_key
*cur
;
268 for (cur
= parent
; cur
; cur
= cur
->next
)
269 if (grub_strcmp (cur
->name
, name
) == 0)
274 struct grub_xnu_devtree_key
*
275 grub_xnu_create_key (struct grub_xnu_devtree_key
**parent
, char *name
)
277 struct grub_xnu_devtree_key
*ret
;
278 ret
= grub_xnu_find_key (*parent
, name
);
281 ret
= (struct grub_xnu_devtree_key
*) grub_malloc (sizeof (*ret
));
284 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't create key %s", name
);
287 ret
->name
= grub_strdup (name
);
291 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't create key %s", name
);
295 ret
->first_child
= 0;
301 struct grub_xnu_devtree_key
*
302 grub_xnu_create_value (struct grub_xnu_devtree_key
**parent
, char *name
)
304 struct grub_xnu_devtree_key
*ret
;
305 ret
= grub_xnu_find_key (*parent
, name
);
308 if (ret
->datasize
== -1)
309 grub_xnu_free_devtree (ret
->first_child
);
310 else if (ret
->datasize
)
311 grub_free (ret
->data
);
316 ret
= (struct grub_xnu_devtree_key
*) grub_malloc (sizeof (*ret
));
319 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't create value %s", name
);
322 ret
->name
= grub_strdup (name
);
326 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't create value %s", name
);
337 grub_xnu_unload (void)
339 grub_xnu_free_devtree (grub_xnu_devtree_root
);
340 grub_xnu_devtree_root
= 0;
342 /* Free loaded image. */
344 driverspackagenum
= 0;
345 grub_free (grub_xnu_heap_start
);
346 grub_xnu_heap_start
= 0;
347 grub_xnu_heap_size
= 0;
349 return GRUB_ERR_NONE
;
353 grub_cmd_xnu_kernel (grub_command_t cmd
__attribute__ ((unused
)),
354 int argc
, char *args
[])
358 grub_addr_t startcode
, endcode
;
360 char *ptr
, *loadaddr
;
363 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
367 macho
= grub_macho_open (args
[0]);
370 if (! grub_macho_contains_macho32 (macho
))
372 grub_macho_close (macho
);
373 return grub_error (GRUB_ERR_BAD_OS
,
374 "Kernel doesn't contain suitable architecture");
377 err
= grub_macho32_size (macho
, &startcode
, &endcode
, GRUB_MACHO_NOBSS
);
380 grub_macho_close (macho
);
385 grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
386 (unsigned long) endcode
, (unsigned long) startcode
);
388 loadaddr
= grub_xnu_heap_malloc (endcode
- startcode
);
389 grub_xnu_heap_will_be_at
= startcode
;
393 grub_macho_close (macho
);
395 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
396 "not enough memory to load kernel");
400 err
= grub_macho32_load (macho
, loadaddr
- startcode
, GRUB_MACHO_NOBSS
);
403 grub_macho_close (macho
);
408 grub_xnu_entry_point
= grub_macho32_get_entry_point (macho
);
409 if (! grub_xnu_entry_point
)
411 grub_macho_close (macho
);
413 return grub_error (GRUB_ERR_BAD_OS
, "couldn't find entry point");
416 grub_macho_close (macho
);
418 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
425 /* Copy parameters to kernel command line. */
426 ptr
= grub_xnu_cmdline
;
427 for (i
= 1; i
< argc
; i
++)
429 if (ptr
+ grub_strlen (args
[i
]) + 1
430 >= grub_xnu_cmdline
+ sizeof (grub_xnu_cmdline
))
432 grub_memcpy (ptr
, args
[i
], grub_strlen (args
[i
]));
433 ptr
+= grub_strlen (args
[i
]);
438 /* Replace last space by '\0'. */
439 if (ptr
!= grub_xnu_cmdline
)
442 err
= grub_cpu_xnu_fill_devicetree ();
446 grub_loader_set (grub_xnu_boot
, grub_xnu_unload
, 0);
452 /* Register a memory in a memory map under name PREFIXSUFFIX
453 and increment SUFFIX. */
455 grub_xnu_register_memory (char *prefix
, int *suffix
,
456 void *addr
, grub_size_t size
)
458 struct grub_xnu_devtree_key
*chosen
;
459 struct grub_xnu_devtree_key
*memorymap
;
460 struct grub_xnu_devtree_key
*driverkey
;
461 struct grub_xnu_extdesc
*extdesc
;
463 if (! grub_xnu_heap_size
)
464 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
466 chosen
= grub_xnu_create_key (&grub_xnu_devtree_root
, "chosen");
469 memorymap
= grub_xnu_create_key (&(chosen
->first_child
), "memory-map");
473 driverkey
= (struct grub_xnu_devtree_key
*) grub_malloc (sizeof (*driverkey
));
475 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't register memory");
478 driverkey
->name
= grub_malloc (grub_strlen (prefix
) + 10);
479 if (!driverkey
->name
)
480 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't register memory");
481 grub_sprintf (driverkey
->name
, "%s%d", prefix
, (*suffix
)++);
484 driverkey
->name
= grub_strdup (prefix
);
485 if (! driverkey
->name
)
486 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't register extension");
487 driverkey
->datasize
= sizeof (*extdesc
);
488 driverkey
->next
= memorymap
->first_child
;
489 memorymap
->first_child
= driverkey
;
490 driverkey
->data
= extdesc
491 = (struct grub_xnu_extdesc
*) grub_malloc (sizeof (*extdesc
));
492 if (! driverkey
->data
)
493 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "can't register extension");
494 extdesc
->addr
= grub_xnu_heap_will_be_at
+
495 ((grub_uint8_t
*) addr
- (grub_uint8_t
*) grub_xnu_heap_start
);
496 extdesc
->size
= (grub_uint32_t
) size
;
497 return GRUB_ERR_NONE
;
502 grub_xnu_load_driver (char *infoplistname
, grub_file_t binaryfile
)
506 grub_file_t infoplist
;
507 struct grub_xnu_extheader
*exthead
;
508 int neededspace
= sizeof (*exthead
);
510 grub_size_t infoplistsize
= 0, machosize
= 0;
512 if (! grub_xnu_heap_size
)
513 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
515 /* Compute the needed space. */
518 macho
= grub_macho_file (binaryfile
);
519 if (! macho
|| ! grub_macho_contains_macho32 (macho
))
522 grub_macho_close (macho
);
523 return grub_error (GRUB_ERR_BAD_OS
,
524 "Extension doesn't contain suitable architecture");
526 machosize
= grub_macho32_filesize (macho
);
527 neededspace
+= machosize
;
533 infoplist
= grub_gzfile_open (infoplistname
, 1);
536 grub_errno
= GRUB_ERR_NONE
;
539 infoplistsize
= grub_file_size (infoplist
);
540 neededspace
+= infoplistsize
+ 1;
545 /* Allocate the space. */
546 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
549 buf
= grub_xnu_heap_malloc (neededspace
);
551 exthead
= (struct grub_xnu_extheader
*) buf
;
552 grub_memset (exthead
, 0, sizeof (*exthead
));
553 buf
+= sizeof (*exthead
);
555 /* Load the binary. */
558 exthead
->binaryaddr
= (buf
- grub_xnu_heap_start
)
559 + grub_xnu_heap_will_be_at
;
560 exthead
->binarysize
= machosize
;
561 if ((err
= grub_macho32_readfile (macho
, buf
)))
563 grub_macho_close (macho
);
566 grub_macho_close (macho
);
569 grub_errno
= GRUB_ERR_NONE
;
571 /* Load the plist. */
574 exthead
->infoplistaddr
= (buf
- grub_xnu_heap_start
)
575 + grub_xnu_heap_will_be_at
;
576 exthead
->infoplistsize
= infoplistsize
+ 1;
577 if (grub_file_read (infoplist
, buf
, infoplistsize
)
578 != (grub_ssize_t
) (infoplistsize
))
580 grub_file_close (infoplist
);
582 return grub_error (GRUB_ERR_BAD_OS
, "Couldn't read file %s: ",
585 grub_file_close (infoplist
);
586 buf
[infoplistsize
] = 0;
588 grub_errno
= GRUB_ERR_NONE
;
590 /* Announce to kernel */
591 return grub_xnu_register_memory ("Driver-", &driversnum
, exthead
,
597 grub_cmd_xnu_mkext (grub_command_t cmd
__attribute__ ((unused
)),
598 int argc
, char *args
[])
603 grub_off_t readoff
= 0;
604 grub_ssize_t readlen
= -1;
605 struct grub_macho_fat_header head
;
606 struct grub_macho_fat_arch
*archs
;
610 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
612 if (! grub_xnu_heap_size
)
613 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
615 file
= grub_gzfile_open (args
[0], 1);
617 return grub_error (GRUB_ERR_FILE_NOT_FOUND
,
618 "Couldn't load driver package");
620 /* Sometimes caches are fat binary. Errgh. */
621 if (grub_file_read (file
, &head
, sizeof (head
))
622 != (grub_ssize_t
) (sizeof (head
)))
624 /* I don't know the internal structure of package but
625 can hardly imagine a valid package shorter than 20 bytes. */
626 grub_file_close (file
);
628 return grub_error (GRUB_ERR_BAD_OS
, "Couldn't read file %s", args
[0]);
631 /* Find the corresponding architecture. */
632 if (grub_be_to_cpu32 (head
.magic
) == GRUB_MACHO_FAT_MAGIC
)
634 narchs
= grub_be_to_cpu32 (head
.nfat_arch
);
635 archs
= grub_malloc (sizeof (struct grub_macho_fat_arch
) * narchs
);
638 grub_file_close (file
);
640 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
641 "Couldn't read file %s", args
[0]);
644 if (grub_file_read (file
, archs
,
645 sizeof (struct grub_macho_fat_arch
) * narchs
)
646 != (grub_ssize_t
) sizeof(struct grub_macho_fat_arch
) * narchs
)
650 return grub_error (GRUB_ERR_READ_ERROR
, "Cannot read fat header.");
652 for (i
= 0; i
< narchs
; i
++)
654 if (GRUB_MACHO_CPUTYPE_IS_HOST32
655 (grub_be_to_cpu32 (archs
[i
].cputype
)))
657 readoff
= grub_be_to_cpu32 (archs
[i
].offset
);
658 readlen
= grub_be_to_cpu32 (archs
[i
].size
);
665 /* It's a flat file. Some sane people still exist. */
667 readlen
= grub_file_size (file
);
672 grub_file_close (file
);
673 return grub_error (GRUB_ERR_BAD_OS
, "no suitable architecture is found");
676 /* Allocate space. */
677 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
680 grub_file_close (file
);
684 loadto
= grub_xnu_heap_malloc (readlen
);
687 grub_file_close (file
);
692 grub_file_seek (file
, readoff
);
693 if (grub_file_read (file
, loadto
, readlen
) != (grub_ssize_t
) (readlen
))
695 grub_file_close (file
);
697 return grub_error (GRUB_ERR_BAD_OS
, "Couldn't read file %s", args
[0]);
699 grub_file_close (file
);
701 /* Pass it to kernel. */
702 return grub_xnu_register_memory ("DriversPackage-", &driverspackagenum
,
707 grub_cmd_xnu_ramdisk (grub_command_t cmd
__attribute__ ((unused
)),
708 int argc
, char *args
[])
716 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
718 if (! grub_xnu_heap_size
)
719 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
721 file
= grub_gzfile_open (args
[0], 1);
723 return grub_error (GRUB_ERR_FILE_NOT_FOUND
,
724 "Couldn't load ramdisk");
726 err
= grub_xnu_align_heap (GRUB_XNU_PAGESIZE
);
730 size
= grub_file_size (file
);
732 loadto
= grub_xnu_heap_malloc (size
);
735 if (grub_file_read (file
, loadto
, size
)
736 != (grub_ssize_t
) (size
))
738 grub_file_close (file
);
740 return grub_error (GRUB_ERR_BAD_OS
, "Couldn't read file %s", args
[0]);
742 return grub_xnu_register_memory ("RAMDisk", 0, loadto
, size
);
745 /* Parse a devtree file. It uses the following format:
750 keyname, valuename and valuedata are in hex.
753 grub_xnu_parse_devtree (struct grub_xnu_devtree_key
**parent
,
754 char *start
, char *end
)
758 int namelen
, datalen
, i
;
759 for (ptr
= start
; ptr
&& ptr
< end
; )
761 if (grub_isspace (*ptr
))
770 /* Parse the name. */
771 for (ptr2
= ptr
; ptr2
< end
&& (grub_isspace (*ptr2
)
772 || (*ptr2
>= '0' && *ptr2
<= '9')
773 || (*ptr2
>= 'a' && *ptr2
<= 'f')
774 || (*ptr2
>= 'A' && *ptr2
<= 'F'));
776 if (! grub_isspace (*ptr2
))
781 name
= grub_malloc (namelen
+ 1);
784 for (i
= 0; i
< 2 * namelen
; i
++)
787 while (grub_isspace (*ptr
))
789 if (*ptr
>= '0' && *ptr
<= '9')
791 if (*ptr
>= 'a' && *ptr
<= 'f')
792 hex
= *ptr
- 'a' + 10;
793 if (*ptr
>= 'A' && *ptr
<= 'F')
794 hex
= *ptr
- 'A' + 10;
797 name
[i
/ 2] = hex
<< 4;
803 while (grub_isspace (*ptr
))
806 /* If it describes a key recursively invoke the function. */
809 struct grub_xnu_devtree_key
*newkey
810 = grub_xnu_create_key (parent
, name
);
814 ptr
= grub_xnu_parse_devtree (&(newkey
->first_child
), ptr
+ 1, end
);
818 /* Parse the data. */
823 for (ptr2
= ptr
; ptr2
< end
&& (grub_isspace (*ptr2
)
824 || (*ptr2
>= '0' && *ptr2
<= '9')
825 || (*ptr2
>= 'a' && *ptr2
<= 'f')
826 || (*ptr2
>= 'A' && *ptr2
<= 'F'));
828 if (! grub_isspace (*ptr2
))
833 data
= grub_malloc (datalen
);
836 for (i
= 0; i
< 2 * datalen
; i
++)
839 while (grub_isspace (*ptr
))
841 if (*ptr
>= '0' && *ptr
<= '9')
843 if (*ptr
>= 'a' && *ptr
<= 'f')
844 hex
= *ptr
- 'a' + 10;
845 if (*ptr
>= 'A' && *ptr
<= 'F')
846 hex
= *ptr
- 'A' + 10;
849 data
[i
/ 2] = hex
<< 4;
854 while (ptr
< end
&& grub_isspace (*ptr
))
857 struct grub_xnu_devtree_key
*newkey
858 = grub_xnu_create_value (parent
, name
);
862 newkey
->datasize
= datalen
;
869 if (ptr
>= end
&& *parent
!= grub_xnu_devtree_root
)
874 /* Returns true if the kext should be loaded according to plist
875 and osbundlereq. Also fill BINNAME. */
877 grub_xnu_check_os_bundle_required (char *plistname
, char *osbundlereq
,
881 char *buf
= 0, *tagstart
= 0, *ptr1
= 0, *keyptr
= 0;
882 char *stringptr
= 0, *ptr2
= 0;
886 int osbundlekeyfound
= 0, binnamekeyfound
= 0;
890 file
= grub_gzfile_open (plistname
, 1);
893 grub_file_close (file
);
895 grub_error (GRUB_ERR_BAD_OS
, "Couldn't read file %s", plistname
);
899 size
= grub_file_size (file
);
900 buf
= grub_malloc (size
);
903 grub_file_close (file
);
905 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "Couldn't read file %s", plistname
);
908 if (grub_file_read (file
, buf
, size
) != (grub_ssize_t
) (size
))
910 grub_file_close (file
);
912 grub_error (GRUB_ERR_BAD_OS
, "Couldn't read file %s", plistname
);
915 grub_file_close (file
);
917 /* Set the return value for the case when no OSBundleRequired tag is found. */
919 ret
= grub_strword (osbundlereq
, "all") || grub_strword (osbundlereq
, "-");
923 /* Parse plist. It's quite dirty and inextensible but does its job. */
924 for (ptr1
= buf
; ptr1
< buf
+ size
; ptr1
++)
930 if (keyptr
&& depth
== 4
931 && grub_strcmp (keyptr
, "OSBundleRequired") == 0)
932 osbundlekeyfound
= 1;
933 if (keyptr
&& depth
== 4 &&
934 grub_strcmp (keyptr
, "CFBundleExecutable") == 0)
936 if (stringptr
&& osbundlekeyfound
&& osbundlereq
&& depth
== 4)
938 for (ptr2
= stringptr
; *ptr2
; ptr2
++)
939 *ptr2
= grub_tolower (*ptr2
);
940 ret
= grub_strword (osbundlereq
, stringptr
)
941 || grub_strword (osbundlereq
, "all");
943 if (stringptr
&& binnamekeyfound
&& binname
&& depth
== 4)
946 grub_free (*binname
);
947 *binname
= grub_strdup (stringptr
);
958 grub_error (GRUB_ERR_BAD_OS
, "can't parse %s", plistname
);
962 if (tagstart
[1] == '?' || ptr1
[-1] == '/')
964 osbundlekeyfound
= 0;
968 if (depth
== 3 && grub_strcmp (tagstart
+ 1, "key") == 0)
970 if (depth
== 3 && grub_strcmp (tagstart
+ 1, "string") == 0)
971 stringptr
= ptr1
+ 1;
972 else if (grub_strcmp (tagstart
+ 1, "/key") != 0)
974 osbundlekeyfound
= 0;
979 if (tagstart
[1] == '/')
990 /* Load all loadable kexts placed under DIRNAME and matching OSBUNDLEREQUIRED */
992 grub_xnu_scan_dir_for_kexts (char *dirname
, char *osbundlerequired
,
1000 auto int load_hook (const char *filename
,
1001 const struct grub_dirhook_info
*info
);
1002 int load_hook (const char *filename
, const struct grub_dirhook_info
*info
)
1007 if (filename
[0] == '.')
1010 if (grub_strlen (filename
) < 5 ||
1011 grub_memcmp (filename
+ grub_strlen (filename
) - 5, ".kext", 5) != 0)
1015 = grub_malloc (grub_strlen (dirname
) + grub_strlen (filename
) + 2);
1017 /* It's a .kext. Try to load it. */
1020 grub_strcpy (newdirname
, dirname
);
1021 newdirname
[grub_strlen (newdirname
) + 1] = 0;
1022 newdirname
[grub_strlen (newdirname
)] = '/';
1023 grub_strcpy (newdirname
+ grub_strlen (newdirname
), filename
);
1024 grub_xnu_load_kext_from_dir (newdirname
, osbundlerequired
,
1026 if (grub_errno
== GRUB_ERR_BAD_OS
)
1027 grub_errno
= GRUB_ERR_NONE
;
1028 grub_free (newdirname
);
1033 if (! grub_xnu_heap_size
)
1034 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
1036 device_name
= grub_file_get_device_name (dirname
);
1037 dev
= grub_device_open (device_name
);
1040 fs
= grub_fs_probe (dev
);
1041 path
= grub_strchr (dirname
, ')');
1048 (fs
->dir
) (dev
, path
, load_hook
);
1049 grub_device_close (dev
);
1051 grub_free (device_name
);
1053 return GRUB_ERR_NONE
;
1056 /* Load extension DIRNAME. (extensions are directories in xnu) */
1058 grub_xnu_load_kext_from_dir (char *dirname
, char *osbundlerequired
,
1062 char *plistname
= 0;
1070 grub_file_t binfile
;
1072 auto int load_hook (const char *filename
,
1073 const struct grub_dirhook_info
*info
);
1075 int load_hook (const char *filename
, const struct grub_dirhook_info
*info
)
1077 if (grub_strlen (filename
) > 15)
1079 grub_strcpy (newdirname
+ grub_strlen (dirname
) + 1, filename
);
1081 /* If the kext contains directory "Contents" all real stuff is in
1083 if (info
->dir
&& grub_strcasecmp (filename
, "Contents") == 0)
1084 grub_xnu_load_kext_from_dir (newdirname
, osbundlerequired
,
1087 /* Directory "Plugins" contains nested kexts. */
1088 if (info
->dir
&& grub_strcasecmp (filename
, "Plugins") == 0)
1089 grub_xnu_scan_dir_for_kexts (newdirname
, osbundlerequired
,
1092 /* Directory "MacOS" contains executable, otherwise executable is
1094 if (info
->dir
&& grub_strcasecmp (filename
, "MacOS") == 0)
1097 /* Info.plist is the file which governs our future actions. */
1098 if (! info
->dir
&& grub_strcasecmp (filename
, "Info.plist") == 0
1100 plistname
= grub_strdup (newdirname
);
1104 newdirname
= grub_malloc (grub_strlen (dirname
) + 20);
1106 return grub_error (GRUB_ERR_OUT_OF_MEMORY
, "couldn't allocate buffer");
1107 grub_strcpy (newdirname
, dirname
);
1108 newdirname
[grub_strlen (dirname
)] = '/';
1109 newdirname
[grub_strlen (dirname
) + 1] = 0;
1110 device_name
= grub_file_get_device_name (dirname
);
1111 dev
= grub_device_open (device_name
);
1114 fs
= grub_fs_probe (dev
);
1115 path
= grub_strchr (dirname
, ')');
1121 newpath
= grub_strchr (newdirname
, ')');
1123 newpath
= newdirname
;
1127 /* Look at the directory. */
1129 (fs
->dir
) (dev
, path
, load_hook
);
1131 if (plistname
&& grub_xnu_check_os_bundle_required
1132 (plistname
, osbundlerequired
, &binsuffix
))
1136 /* Open the binary. */
1137 char *binname
= grub_malloc (grub_strlen (dirname
)
1138 + grub_strlen (binsuffix
)
1139 + sizeof ("/MacOS/"));
1140 grub_strcpy (binname
, dirname
);
1142 grub_strcpy (binname
+ grub_strlen (binname
), "/MacOS/");
1144 grub_strcpy (binname
+ grub_strlen (binname
), "/");
1145 grub_strcpy (binname
+ grub_strlen (binname
), binsuffix
);
1146 grub_dprintf ("xnu", "%s:%s\n", plistname
, binname
);
1147 binfile
= grub_gzfile_open (binname
, 1);
1149 grub_errno
= GRUB_ERR_NONE
;
1151 /* Load the extension. */
1152 grub_xnu_load_driver (plistname
, binfile
);
1153 grub_free (binname
);
1154 grub_free (binsuffix
);
1158 grub_dprintf ("xnu", "%s:0\n", plistname
);
1159 grub_xnu_load_driver (plistname
, 0);
1162 grub_free (plistname
);
1163 grub_device_close (dev
);
1165 grub_free (device_name
);
1167 return GRUB_ERR_NONE
;
1170 /* Load devtree file. */
1172 grub_cmd_xnu_devtree (grub_command_t cmd
__attribute__ ((unused
)),
1173 int argc
, char *args
[])
1176 char *data
, *endret
;
1177 grub_size_t datalen
;
1180 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "Filename required");
1182 if (! grub_xnu_heap_size
)
1183 return grub_error (GRUB_ERR_BAD_OS
, "no xnu kernel loaded");
1185 /* Load the file. */
1186 file
= grub_gzfile_open (args
[0], 1);
1188 return grub_error (GRUB_ERR_FILE_NOT_FOUND
, "Couldn't load device tree");
1189 datalen
= grub_file_size (file
);
1190 data
= grub_malloc (datalen
+ 1);
1193 grub_file_close (file
);
1194 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
1195 "Could load device tree into memory");
1197 if (grub_file_read (file
, data
, datalen
) != (grub_ssize_t
) datalen
)
1199 grub_file_close (file
);
1202 return grub_error (GRUB_ERR_BAD_OS
, "Couldn't read file %s", args
[0]);
1204 grub_file_close (file
);
1207 /* Parse the file. */
1208 endret
= grub_xnu_parse_devtree (&grub_xnu_devtree_root
,
1209 data
, data
+ datalen
);
1213 return grub_error (GRUB_ERR_BAD_OS
, "Couldn't parse devtree");
1215 return GRUB_ERR_NONE
;
1218 static int locked
=0;
1219 static grub_dl_t my_mod
;
1221 /* Load the kext. */
1223 grub_cmd_xnu_kext (grub_command_t cmd
__attribute__ ((unused
)),
1224 int argc
, char *args
[])
1226 grub_file_t binfile
= 0;
1229 /* User explicitly specified plist and binary. */
1230 if (grub_strcmp (args
[1], "-") != 0)
1232 binfile
= grub_gzfile_open (args
[1], 1);
1235 grub_error (GRUB_ERR_BAD_OS
, "can't open file");
1236 return GRUB_ERR_NONE
;
1239 return grub_xnu_load_driver (grub_strcmp (args
[0], "-") ? args
[0] : 0,
1243 /* load kext normally. */
1245 return grub_xnu_load_kext_from_dir (args
[0], 0, 10);
1247 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
1250 /* Load a directory containing kexts. */
1252 grub_cmd_xnu_kextdir (grub_command_t cmd
__attribute__ ((unused
)),
1253 int argc
, char *args
[])
1255 if (argc
!= 1 && argc
!= 2)
1256 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "directory name required");
1259 return grub_xnu_scan_dir_for_kexts (args
[0],
1260 "console,root,local-root,network-root",
1264 char *osbundlerequired
= grub_strdup (args
[1]), *ptr
;
1266 if (! osbundlerequired
)
1267 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
1268 "couldn't allocate string temporary space");
1269 for (ptr
= osbundlerequired
; *ptr
; ptr
++)
1270 *ptr
= grub_tolower (*ptr
);
1271 err
= grub_xnu_scan_dir_for_kexts (args
[0], osbundlerequired
, 10);
1272 grub_free (osbundlerequired
);
1277 struct grub_video_bitmap
*grub_xnu_bitmap
= 0;
1280 grub_cmd_xnu_splash (grub_command_t cmd
__attribute__ ((unused
)),
1281 int argc
, char *args
[])
1285 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
1287 err
= grub_video_bitmap_load (&grub_xnu_bitmap
, args
[0]);
1289 grub_xnu_bitmap
= 0;
1296 grub_cmd_xnu_resume (grub_command_t cmd
__attribute__ ((unused
)),
1297 int argc
, char *args
[])
1300 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "file name required");
1302 return grub_xnu_resume (args
[0]);
1310 grub_dl_ref (my_mod
);
1318 grub_dl_unref (my_mod
);
1322 static grub_command_t cmd_kernel
, cmd_mkext
, cmd_kext
, cmd_kextdir
,
1323 cmd_ramdisk
, cmd_devtree
, cmd_resume
, cmd_splash
;
1327 cmd_kernel
= grub_register_command ("xnu_kernel", grub_cmd_xnu_kernel
, 0,
1328 "load a xnu kernel");
1329 cmd_mkext
= grub_register_command ("xnu_mkext", grub_cmd_xnu_mkext
, 0,
1330 "Load XNU extension package.");
1331 cmd_kext
= grub_register_command ("xnu_kext", grub_cmd_xnu_kext
, 0,
1332 "Load XNU extension.");
1333 cmd_kextdir
= grub_register_command ("xnu_kextdir", grub_cmd_xnu_kextdir
,
1334 "xnu_kextdir DIRECTORY [OSBundleRequired]",
1335 "Load XNU extension directory");
1336 cmd_ramdisk
= grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk
, 0,
1337 "Load XNU ramdisk. "
1338 "It will be seen as md0");
1339 cmd_devtree
= grub_register_command ("xnu_devtree", grub_cmd_xnu_devtree
, 0,
1340 "Load XNU devtree");
1341 cmd_splash
= grub_register_command ("xnu_splash", grub_cmd_xnu_splash
, 0,
1342 "Load a splash image for XNU");
1345 cmd_resume
= grub_register_command ("xnu_resume", grub_cmd_xnu_resume
,
1346 0, "Load XNU hibernate image.");
1354 grub_unregister_command (cmd_resume
);
1356 grub_unregister_command (cmd_mkext
);
1357 grub_unregister_command (cmd_kext
);
1358 grub_unregister_command (cmd_kextdir
);
1359 grub_unregister_command (cmd_devtree
);
1360 grub_unregister_command (cmd_ramdisk
);
1361 grub_unregister_command (cmd_kernel
);
1362 grub_unregister_command (cmd_splash
);