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
struct grub_xnu_devtree_key *grub_xnu_devtree_root = 0;
38
static int driverspackagenum = 0;
39
static int driversnum = 0;
40
int grub_xnu_is_64bit = 0;
42
grub_addr_t grub_xnu_heap_target_start = 0;
43
grub_size_t grub_xnu_heap_size = 0;
44
struct grub_relocator *grub_xnu_relocator;
47
grub_xnu_register_memory (char *prefix, int *suffix,
48
grub_addr_t addr, grub_size_t size);
50
grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target)
53
grub_relocator_chunk_t ch;
55
err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch,
56
grub_xnu_heap_target_start
57
+ grub_xnu_heap_size, size);
61
*src = get_virtual_current_address (ch);
62
*target = grub_xnu_heap_target_start + grub_xnu_heap_size;
63
grub_xnu_heap_size += size;
64
grub_dprintf ("xnu", "val=%p\n", *src);
68
/* Make sure next block of the heap will be aligned.
69
Please notice: aligned are pointers AFTER relocation
70
and not the current ones. */
72
grub_xnu_align_heap (int align)
75
= ALIGN_UP (grub_xnu_heap_target_start+ grub_xnu_heap_size, align)
76
- grub_xnu_heap_target_start;
80
/* Free subtree pointed by CUR. */
82
grub_xnu_free_devtree (struct grub_xnu_devtree_key *cur)
84
struct grub_xnu_devtree_key *d;
87
grub_free (cur->name);
88
if (cur->datasize == -1)
89
grub_xnu_free_devtree (cur->first_child);
91
grub_free (cur->data);
98
/* Compute the size of device tree in xnu format. */
100
grub_xnu_writetree_get_size (struct grub_xnu_devtree_key *start, char *name)
103
struct grub_xnu_devtree_key *cur;
106
ret = 2 * sizeof (grub_uint32_t);
109
ret += 32 + sizeof (grub_uint32_t)
110
+ grub_strlen (name) + 4
111
- (grub_strlen (name) % 4);
113
for (cur = start; cur; cur = cur->next)
114
if (cur->datasize != -1)
118
align_overhead = 4 - (cur->datasize % 4);
119
if (align_overhead == 4)
121
ret += 32 + sizeof (grub_uint32_t) + cur->datasize + align_overhead;
124
ret += grub_xnu_writetree_get_size (cur->first_child, cur->name);
128
/* Write devtree in XNU format at curptr assuming the head is named NAME.*/
130
grub_xnu_writetree_toheap_real (void *curptr,
131
struct grub_xnu_devtree_key *start, char *name)
133
struct grub_xnu_devtree_key *cur;
134
int nkeys = 0, nvals = 0;
135
for (cur = start; cur; cur = cur->next)
137
if (cur->datasize == -1)
145
*((grub_uint32_t *) curptr) = nvals;
146
curptr = ((grub_uint32_t *) curptr) + 1;
147
*((grub_uint32_t *) curptr) = nkeys;
148
curptr = ((grub_uint32_t *) curptr) + 1;
150
/* First comes "name" value. */
151
grub_memset (curptr, 0, 32);
152
grub_memcpy (curptr, "name", 4);
153
curptr = ((grub_uint8_t *) curptr) + 32;
154
*((grub_uint32_t *)curptr) = grub_strlen (name) + 1;
155
curptr = ((grub_uint32_t *) curptr) + 1;
156
grub_memcpy (curptr, name, grub_strlen (name));
157
curptr = ((grub_uint8_t *) curptr) + grub_strlen (name);
158
grub_memset (curptr, 0, 4 - (grub_strlen (name) % 4));
159
curptr = ((grub_uint8_t *) curptr) + (4 - (grub_strlen (name) % 4));
161
/* Then the other values. */
162
for (cur = start; cur; cur = cur->next)
163
if (cur->datasize != -1)
167
align_overhead = 4 - (cur->datasize % 4);
168
if (align_overhead == 4)
170
grub_memset (curptr, 0, 32);
171
grub_strncpy (curptr, cur->name, 31);
172
curptr = ((grub_uint8_t *) curptr) + 32;
173
*((grub_uint32_t *) curptr) = cur->datasize;
174
curptr = ((grub_uint32_t *) curptr) + 1;
175
grub_memcpy (curptr, cur->data, cur->datasize);
176
curptr = ((grub_uint8_t *) curptr) + cur->datasize;
177
grub_memset (curptr, 0, align_overhead);
178
curptr = ((grub_uint8_t *) curptr) + align_overhead;
181
/* And then the keys. Recursively use this function. */
182
for (cur = start; cur; cur = cur->next)
183
if (cur->datasize == -1)
184
if (!(curptr = grub_xnu_writetree_toheap_real (curptr,
192
grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size)
194
struct grub_xnu_devtree_key *chosen;
195
struct grub_xnu_devtree_key *memorymap;
196
struct grub_xnu_devtree_key *driverkey;
197
struct grub_xnu_extdesc *extdesc;
201
err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
205
/* Device tree itself is in the memory map of device tree. */
206
/* Create a dummy value in memory-map. */
207
chosen = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
210
memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
214
driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*driverkey));
216
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't write device tree");
217
driverkey->name = grub_strdup ("DeviceTree");
218
if (! driverkey->name)
219
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't write device tree");
220
driverkey->datasize = sizeof (*extdesc);
221
driverkey->next = memorymap->first_child;
222
memorymap->first_child = driverkey;
223
driverkey->data = extdesc
224
= (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc));
225
if (! driverkey->data)
226
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't write device tree");
228
/* Allocate the space based on the size with dummy value. */
229
*size = grub_xnu_writetree_get_size (grub_xnu_devtree_root, "/");
230
err = grub_xnu_heap_malloc (ALIGN_UP (*size + 1, GRUB_XNU_PAGESIZE),
235
/* Put real data in the dummy. */
236
extdesc->addr = *target;
237
extdesc->size = (grub_uint32_t) *size;
239
/* Write the tree to heap. */
240
grub_xnu_writetree_toheap_real (src, grub_xnu_devtree_root, "/");
241
return GRUB_ERR_NONE;
244
/* Find a key or value in parent key. */
245
struct grub_xnu_devtree_key *
246
grub_xnu_find_key (struct grub_xnu_devtree_key *parent, char *name)
248
struct grub_xnu_devtree_key *cur;
249
for (cur = parent; cur; cur = cur->next)
250
if (grub_strcmp (cur->name, name) == 0)
255
struct grub_xnu_devtree_key *
256
grub_xnu_create_key (struct grub_xnu_devtree_key **parent, char *name)
258
struct grub_xnu_devtree_key *ret;
259
ret = grub_xnu_find_key (*parent, name);
262
ret = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*ret));
265
grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create key %s", name);
268
ret->name = grub_strdup (name);
272
grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create key %s", name);
281
struct grub_xnu_devtree_key *
282
grub_xnu_create_value (struct grub_xnu_devtree_key **parent, char *name)
284
struct grub_xnu_devtree_key *ret;
285
ret = grub_xnu_find_key (*parent, name);
288
if (ret->datasize == -1)
289
grub_xnu_free_devtree (ret->first_child);
290
else if (ret->datasize)
291
grub_free (ret->data);
296
ret = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*ret));
299
grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create value %s", name);
302
ret->name = grub_strdup (name);
306
grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create value %s", name);
315
grub_xnu_unload (void)
317
grub_cpu_xnu_unload ();
319
grub_xnu_free_devtree (grub_xnu_devtree_root);
320
grub_xnu_devtree_root = 0;
322
/* Free loaded image. */
324
driverspackagenum = 0;
325
grub_relocator_unload (grub_xnu_relocator);
326
grub_xnu_relocator = NULL;
327
grub_xnu_heap_target_start = 0;
328
grub_xnu_heap_size = 0;
330
return GRUB_ERR_NONE;
334
grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
335
int argc, char *args[])
339
grub_uint32_t startcode, endcode;
341
char *ptr, *loadaddr;
342
grub_addr_t loadaddr_target;
345
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
349
macho = grub_macho_open (args[0]);
352
if (! grub_macho_contains_macho32 (macho))
354
grub_macho_close (macho);
355
return grub_error (GRUB_ERR_BAD_OS,
356
"kernel doesn't contain suitable 32-bit architecture");
359
err = grub_macho_size32 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS);
362
grub_macho_close (macho);
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)
373
grub_xnu_heap_target_start = startcode;
374
err = grub_xnu_heap_malloc (endcode - startcode, (void **) &loadaddr,
379
grub_macho_close (macho);
385
err = grub_macho_load32 (macho, loadaddr - startcode, GRUB_MACHO_NOBSS);
388
grub_macho_close (macho);
393
grub_xnu_entry_point = grub_macho_get_entry_point32 (macho);
394
if (! grub_xnu_entry_point)
396
grub_macho_close (macho);
398
return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point");
401
grub_macho_close (macho);
403
err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
410
/* Copy parameters to kernel command line. */
411
ptr = grub_xnu_cmdline;
412
for (i = 1; i < argc; i++)
414
if (ptr + grub_strlen (args[i]) + 1
415
>= grub_xnu_cmdline + sizeof (grub_xnu_cmdline))
417
grub_memcpy (ptr, args[i], grub_strlen (args[i]));
418
ptr += grub_strlen (args[i]);
423
/* Replace last space by '\0'. */
424
if (ptr != grub_xnu_cmdline)
427
grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);
430
grub_xnu_is_64bit = 0;
436
grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
437
int argc, char *args[])
441
grub_uint64_t startcode, endcode;
443
char *ptr, *loadaddr;
444
grub_addr_t loadaddr_target;
447
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
451
macho = grub_macho_open (args[0]);
454
if (! grub_macho_contains_macho64 (macho))
456
grub_macho_close (macho);
457
return grub_error (GRUB_ERR_BAD_OS,
458
"kernel doesn't contain suitable 64-bit architecture");
461
err = grub_macho_size64 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS);
464
grub_macho_close (macho);
469
startcode &= 0x0fffffff;
470
endcode &= 0x0fffffff;
472
grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
473
(unsigned long) endcode, (unsigned long) startcode);
475
grub_xnu_relocator = grub_relocator_new ();
476
if (!grub_xnu_relocator)
478
grub_xnu_heap_target_start = startcode;
479
err = grub_xnu_heap_malloc (endcode - startcode, (void **) &loadaddr,
484
grub_macho_close (macho);
490
err = grub_macho_load64 (macho, loadaddr - startcode, GRUB_MACHO_NOBSS);
493
grub_macho_close (macho);
498
grub_xnu_entry_point = grub_macho_get_entry_point64 (macho) & 0x0fffffff;
499
if (! grub_xnu_entry_point)
501
grub_macho_close (macho);
503
return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point");
506
grub_macho_close (macho);
508
err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
515
/* Copy parameters to kernel command line. */
516
ptr = grub_xnu_cmdline;
517
for (i = 1; i < argc; i++)
519
if (ptr + grub_strlen (args[i]) + 1
520
>= grub_xnu_cmdline + sizeof (grub_xnu_cmdline))
522
grub_memcpy (ptr, args[i], grub_strlen (args[i]));
523
ptr += grub_strlen (args[i]);
528
/* Replace last space by '\0'. */
529
if (ptr != grub_xnu_cmdline)
532
grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);
535
grub_xnu_is_64bit = 1;
540
/* Register a memory in a memory map under name PREFIXSUFFIX
541
and increment SUFFIX. */
543
grub_xnu_register_memory (char *prefix, int *suffix,
544
grub_addr_t addr, grub_size_t size)
546
struct grub_xnu_devtree_key *chosen;
547
struct grub_xnu_devtree_key *memorymap;
548
struct grub_xnu_devtree_key *driverkey;
549
struct grub_xnu_extdesc *extdesc;
551
if (! grub_xnu_heap_size)
552
return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
554
chosen = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
557
memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
561
driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*driverkey));
563
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register memory");
566
driverkey->name = grub_xasprintf ("%s%d", prefix, (*suffix)++);
567
if (!driverkey->name)
568
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register memory");
571
driverkey->name = grub_strdup (prefix);
572
if (! driverkey->name)
573
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register extension");
574
driverkey->datasize = sizeof (*extdesc);
575
driverkey->next = memorymap->first_child;
576
memorymap->first_child = driverkey;
577
driverkey->data = extdesc
578
= (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc));
579
if (! driverkey->data)
580
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register extension");
581
extdesc->addr = addr;
582
extdesc->size = (grub_uint32_t) size;
583
return GRUB_ERR_NONE;
587
get_name_ptr (char *name)
590
/* Skip Info.plist. */
591
p2 = grub_strrchr (p, '/');
598
p2 = grub_strrchr (p, '/');
603
if (grub_memcmp (p2, "/Contents/", sizeof ("/Contents/") - 1) != 0)
608
p2 = grub_strrchr (p, '/');
616
grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile)
620
grub_file_t infoplist;
621
struct grub_xnu_extheader *exthead;
622
int neededspace = sizeof (*exthead);
623
grub_uint8_t *buf, *buf0;
624
grub_addr_t buf_target;
625
grub_size_t infoplistsize = 0, machosize = 0;
626
char *name, *nameend;
629
name = get_name_ptr (infoplistname);
630
nameend = grub_strchr (name, '/');
633
namelen = nameend - name;
635
namelen = grub_strlen (name);
637
neededspace += namelen + 1;
639
if (! grub_xnu_heap_size)
640
return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
642
/* Compute the needed space. */
645
macho = grub_macho_file (binaryfile);
646
if (! macho || ! grub_macho_contains_macho32 (macho))
649
grub_macho_close (macho);
650
return grub_error (GRUB_ERR_BAD_OS,
651
"extension doesn't contain suitable architecture");
653
if (grub_xnu_is_64bit)
654
machosize = grub_macho_filesize64 (macho);
656
machosize = grub_macho_filesize32 (macho);
657
neededspace += machosize;
663
infoplist = grub_file_open (infoplistname);
666
grub_errno = GRUB_ERR_NONE;
669
infoplistsize = grub_file_size (infoplist);
670
neededspace += infoplistsize + 1;
675
/* Allocate the space. */
676
err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
679
err = grub_xnu_heap_malloc (neededspace, (void **) &buf0, &buf_target);
684
exthead = (struct grub_xnu_extheader *) buf;
685
grub_memset (exthead, 0, sizeof (*exthead));
686
buf += sizeof (*exthead);
688
/* Load the binary. */
691
exthead->binaryaddr = buf_target + (buf - buf0);
692
exthead->binarysize = machosize;
693
if (grub_xnu_is_64bit)
694
err = grub_macho_readfile64 (macho, buf);
696
err = grub_macho_readfile32 (macho, buf);
699
grub_macho_close (macho);
702
grub_macho_close (macho);
705
grub_errno = GRUB_ERR_NONE;
707
/* Load the plist. */
710
exthead->infoplistaddr = buf_target + (buf - buf0);
711
exthead->infoplistsize = infoplistsize + 1;
712
if (grub_file_read (infoplist, buf, infoplistsize)
713
!= (grub_ssize_t) (infoplistsize))
715
grub_file_close (infoplist);
717
return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s: ",
720
grub_file_close (infoplist);
721
buf[infoplistsize] = 0;
722
buf += infoplistsize + 1;
724
grub_errno = GRUB_ERR_NONE;
726
exthead->nameaddr = (buf - buf0) + buf_target;
727
exthead->namesize = namelen + 1;
728
grub_memcpy (buf, name, namelen);
732
/* Announce to kernel */
733
return grub_xnu_register_memory ("Driver-", &driversnum, buf_target,
739
grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)),
740
int argc, char *args[])
744
grub_addr_t loadto_target;
746
grub_off_t readoff = 0;
747
grub_ssize_t readlen = -1;
748
struct grub_macho_fat_header head;
749
struct grub_macho_fat_arch *archs;
753
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
755
if (! grub_xnu_heap_size)
756
return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
758
file = grub_file_open (args[0]);
760
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
761
"couldn't load driver package");
763
/* Sometimes caches are fat binary. Errgh. */
764
if (grub_file_read (file, &head, sizeof (head))
765
!= (grub_ssize_t) (sizeof (head)))
767
/* I don't know the internal structure of package but
768
can hardly imagine a valid package shorter than 20 bytes. */
769
grub_file_close (file);
771
return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]);
774
/* Find the corresponding architecture. */
775
if (grub_be_to_cpu32 (head.magic) == GRUB_MACHO_FAT_MAGIC)
777
narchs = grub_be_to_cpu32 (head.nfat_arch);
778
archs = grub_malloc (sizeof (struct grub_macho_fat_arch) * narchs);
781
grub_file_close (file);
783
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
784
"couldn't read file %s", args[0]);
787
if (grub_file_read (file, archs,
788
sizeof (struct grub_macho_fat_arch) * narchs)
789
!= (grub_ssize_t) sizeof(struct grub_macho_fat_arch) * narchs)
793
return grub_error (GRUB_ERR_READ_ERROR, "cannot read fat header");
795
for (i = 0; i < narchs; i++)
797
if (!grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST32
798
(grub_be_to_cpu32 (archs[i].cputype)))
800
readoff = grub_be_to_cpu32 (archs[i].offset);
801
readlen = grub_be_to_cpu32 (archs[i].size);
803
if (grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST64
804
(grub_be_to_cpu32 (archs[i].cputype)))
806
readoff = grub_be_to_cpu32 (archs[i].offset);
807
readlen = grub_be_to_cpu32 (archs[i].size);
814
/* It's a flat file. Some sane people still exist. */
816
readlen = grub_file_size (file);
821
grub_file_close (file);
822
return grub_error (GRUB_ERR_BAD_OS, "no suitable architecture is found");
825
/* Allocate space. */
826
err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
829
grub_file_close (file);
833
err = grub_xnu_heap_malloc (readlen, &loadto, &loadto_target);
836
grub_file_close (file);
841
grub_file_seek (file, readoff);
842
if (grub_file_read (file, loadto, readlen) != (grub_ssize_t) (readlen))
844
grub_file_close (file);
846
return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]);
848
grub_file_close (file);
850
/* Pass it to kernel. */
851
return grub_xnu_register_memory ("DriversPackage-", &driverspackagenum,
852
loadto_target, readlen);
856
grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)),
857
int argc, char *args[])
861
grub_addr_t loadto_target;
866
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
868
if (! grub_xnu_heap_size)
869
return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
871
file = grub_file_open (args[0]);
873
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
874
"couldn't load ramdisk");
876
err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
880
size = grub_file_size (file);
882
err = grub_xnu_heap_malloc (size, &loadto, &loadto_target);
885
if (grub_file_read (file, loadto, size)
886
!= (grub_ssize_t) (size))
888
grub_file_close (file);
890
return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]);
892
return grub_xnu_register_memory ("RAMDisk", 0, loadto_target, size);
895
/* Returns true if the kext should be loaded according to plist
896
and osbundlereq. Also fill BINNAME. */
898
grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq,
902
char *buf = 0, *tagstart = 0, *ptr1 = 0, *keyptr = 0;
903
char *stringptr = 0, *ptr2 = 0;
907
int osbundlekeyfound = 0, binnamekeyfound = 0;
911
file = grub_file_open (plistname);
914
grub_file_close (file);
916
grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", plistname);
920
size = grub_file_size (file);
921
buf = grub_malloc (size);
924
grub_file_close (file);
926
grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't read file %s", plistname);
929
if (grub_file_read (file, buf, size) != (grub_ssize_t) (size))
931
grub_file_close (file);
933
grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", plistname);
936
grub_file_close (file);
938
/* Set the return value for the case when no OSBundleRequired tag is found. */
940
ret = grub_strword (osbundlereq, "all") || grub_strword (osbundlereq, "-");
944
/* Parse plist. It's quite dirty and inextensible but does its job. */
945
for (ptr1 = buf; ptr1 < buf + size; ptr1++)
951
if (keyptr && depth == 4
952
&& grub_strcmp (keyptr, "OSBundleRequired") == 0)
953
osbundlekeyfound = 1;
954
if (keyptr && depth == 4 &&
955
grub_strcmp (keyptr, "CFBundleExecutable") == 0)
957
if (stringptr && osbundlekeyfound && osbundlereq && depth == 4)
959
for (ptr2 = stringptr; *ptr2; ptr2++)
960
*ptr2 = grub_tolower (*ptr2);
961
ret = grub_strword (osbundlereq, stringptr)
962
|| grub_strword (osbundlereq, "all");
964
if (stringptr && binnamekeyfound && binname && depth == 4)
967
grub_free (*binname);
968
*binname = grub_strdup (stringptr);
979
grub_error (GRUB_ERR_BAD_OS, "can't parse %s", plistname);
983
if (tagstart[1] == '?' || ptr1[-1] == '/')
985
osbundlekeyfound = 0;
989
if (depth == 3 && grub_strcmp (tagstart + 1, "key") == 0)
991
if (depth == 3 && grub_strcmp (tagstart + 1, "string") == 0)
992
stringptr = ptr1 + 1;
993
else if (grub_strcmp (tagstart + 1, "/key") != 0)
995
osbundlekeyfound = 0;
1000
if (tagstart[1] == '/')
1011
/* Load all loadable kexts placed under DIRNAME and matching OSBUNDLEREQUIRED */
1013
grub_xnu_scan_dir_for_kexts (char *dirname, char *osbundlerequired,
1021
auto int load_hook (const char *filename,
1022
const struct grub_dirhook_info *info);
1023
int load_hook (const char *filename, const struct grub_dirhook_info *info)
1028
if (filename[0] == '.')
1031
if (grub_strlen (filename) < 5 ||
1032
grub_memcmp (filename + grub_strlen (filename) - 5, ".kext", 5) != 0)
1036
= grub_malloc (grub_strlen (dirname) + grub_strlen (filename) + 2);
1038
/* It's a .kext. Try to load it. */
1041
grub_strcpy (newdirname, dirname);
1042
newdirname[grub_strlen (newdirname) + 1] = 0;
1043
newdirname[grub_strlen (newdirname)] = '/';
1044
grub_strcpy (newdirname + grub_strlen (newdirname), filename);
1045
grub_xnu_load_kext_from_dir (newdirname, osbundlerequired,
1047
if (grub_errno == GRUB_ERR_BAD_OS)
1048
grub_errno = GRUB_ERR_NONE;
1049
grub_free (newdirname);
1054
if (! grub_xnu_heap_size)
1055
return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
1057
device_name = grub_file_get_device_name (dirname);
1058
dev = grub_device_open (device_name);
1061
fs = grub_fs_probe (dev);
1062
path = grub_strchr (dirname, ')');
1069
(fs->dir) (dev, path, load_hook);
1070
grub_device_close (dev);
1072
grub_free (device_name);
1074
return GRUB_ERR_NONE;
1077
/* Load extension DIRNAME. (extensions are directories in xnu) */
1079
grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired,
1083
char *plistname = 0;
1091
grub_file_t binfile;
1093
auto int load_hook (const char *filename,
1094
const struct grub_dirhook_info *info);
1096
int load_hook (const char *filename, const struct grub_dirhook_info *info)
1098
if (grub_strlen (filename) > 15)
1100
grub_strcpy (newdirname + grub_strlen (dirname) + 1, filename);
1102
/* If the kext contains directory "Contents" all real stuff is in
1104
if (info->dir && grub_strcasecmp (filename, "Contents") == 0)
1105
grub_xnu_load_kext_from_dir (newdirname, osbundlerequired,
1108
/* Directory "Plugins" contains nested kexts. */
1109
if (info->dir && grub_strcasecmp (filename, "Plugins") == 0)
1110
grub_xnu_scan_dir_for_kexts (newdirname, osbundlerequired,
1113
/* Directory "MacOS" contains executable, otherwise executable is
1115
if (info->dir && grub_strcasecmp (filename, "MacOS") == 0)
1118
/* Info.plist is the file which governs our future actions. */
1119
if (! info->dir && grub_strcasecmp (filename, "Info.plist") == 0
1121
plistname = grub_strdup (newdirname);
1125
newdirname = grub_malloc (grub_strlen (dirname) + 20);
1127
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't allocate buffer");
1128
grub_strcpy (newdirname, dirname);
1129
newdirname[grub_strlen (dirname)] = '/';
1130
newdirname[grub_strlen (dirname) + 1] = 0;
1131
device_name = grub_file_get_device_name (dirname);
1132
dev = grub_device_open (device_name);
1135
fs = grub_fs_probe (dev);
1136
path = grub_strchr (dirname, ')');
1142
newpath = grub_strchr (newdirname, ')');
1144
newpath = newdirname;
1148
/* Look at the directory. */
1150
(fs->dir) (dev, path, load_hook);
1152
if (plistname && grub_xnu_check_os_bundle_required
1153
(plistname, osbundlerequired, &binsuffix))
1157
/* Open the binary. */
1158
char *binname = grub_malloc (grub_strlen (dirname)
1159
+ grub_strlen (binsuffix)
1160
+ sizeof ("/MacOS/"));
1161
grub_strcpy (binname, dirname);
1163
grub_strcpy (binname + grub_strlen (binname), "/MacOS/");
1165
grub_strcpy (binname + grub_strlen (binname), "/");
1166
grub_strcpy (binname + grub_strlen (binname), binsuffix);
1167
grub_dprintf ("xnu", "%s:%s\n", plistname, binname);
1168
binfile = grub_file_open (binname);
1170
grub_errno = GRUB_ERR_NONE;
1172
/* Load the extension. */
1173
grub_xnu_load_driver (plistname, binfile);
1174
grub_free (binname);
1175
grub_free (binsuffix);
1179
grub_dprintf ("xnu", "%s:0\n", plistname);
1180
grub_xnu_load_driver (plistname, 0);
1183
grub_free (plistname);
1184
grub_device_close (dev);
1186
grub_free (device_name);
1188
return GRUB_ERR_NONE;
1192
static int locked=0;
1193
static grub_dl_t my_mod;
1195
/* Load the kext. */
1197
grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)),
1198
int argc, char *args[])
1200
grub_file_t binfile = 0;
1203
/* User explicitly specified plist and binary. */
1204
if (grub_strcmp (args[1], "-") != 0)
1206
binfile = grub_file_open (args[1]);
1209
grub_error (GRUB_ERR_BAD_OS, "can't open file");
1210
return GRUB_ERR_NONE;
1213
return grub_xnu_load_driver (grub_strcmp (args[0], "-") ? args[0] : 0,
1217
/* load kext normally. */
1219
return grub_xnu_load_kext_from_dir (args[0], 0, 10);
1221
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
1224
/* Load a directory containing kexts. */
1226
grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ ((unused)),
1227
int argc, char *args[])
1229
if (argc != 1 && argc != 2)
1230
return grub_error (GRUB_ERR_BAD_ARGUMENT, "directory name required");
1233
return grub_xnu_scan_dir_for_kexts (args[0],
1234
"console,root,local-root,network-root",
1238
char *osbundlerequired = grub_strdup (args[1]), *ptr;
1240
if (! osbundlerequired)
1241
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
1242
"couldn't allocate string temporary space");
1243
for (ptr = osbundlerequired; *ptr; ptr++)
1244
*ptr = grub_tolower (*ptr);
1245
err = grub_xnu_scan_dir_for_kexts (args[0], osbundlerequired, 10);
1246
grub_free (osbundlerequired);
1254
if (c >= '0' && c <= '9')
1256
if (c >= 'a' && c <= 'z')
1257
return c - 'a' + 10;
1258
if (c >= 'A' && c <= 'Z')
1259
return c - 'A' + 10;
1264
unescape (char *name, char *curdot, char *nextdot, int *len)
1268
for (ptr = curdot; ptr < nextdot;)
1269
if (ptr + 2 < nextdot && *ptr == '%')
1271
*dptr = (hextoval (ptr[1]) << 4) | (hextoval (ptr[2]));
1285
grub_xnu_fill_devicetree (void)
1287
auto int iterate_env (struct grub_env_var *var);
1288
int iterate_env (struct grub_env_var *var)
1290
char *nextdot = 0, *curdot;
1291
struct grub_xnu_devtree_key **curkey = &grub_xnu_devtree_root;
1292
struct grub_xnu_devtree_key *curvalue;
1293
char *name = 0, *data;
1296
if (grub_memcmp (var->name, "XNU.DeviceTree.",
1297
sizeof ("XNU.DeviceTree.") - 1) != 0)
1300
curdot = var->name + sizeof ("XNU.DeviceTree.") - 1;
1301
nextdot = grub_strchr (curdot, '.');
1306
name = grub_realloc (name, nextdot - curdot + 1);
1311
unescape (name, curdot, nextdot, &len);
1314
curkey = &(grub_xnu_create_key (curkey, name)->first_child);
1317
nextdot = grub_strchr (nextdot, '.');
1322
nextdot = curdot + grub_strlen (curdot) + 1;
1324
name = grub_realloc (name, nextdot - curdot + 1);
1329
unescape (name, curdot, nextdot, &len);
1332
curvalue = grub_xnu_create_value (curkey, name);
1335
data = grub_malloc (grub_strlen (var->value) + 1);
1339
unescape (data, var->value, var->value + grub_strlen (var->value),
1341
curvalue->datasize = len;
1342
curvalue->data = data;
1347
grub_env_iterate (iterate_env);
1352
struct grub_video_bitmap *grub_xnu_bitmap = 0;
1353
grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode;
1355
/* Option array indices. */
1356
#define XNU_SPLASH_CMD_ARGINDEX_MODE 0
1358
static const struct grub_arg_option xnu_splash_cmd_options[] =
1360
{"mode", 'm', 0, "Background image mode.", "stretch|normal",
1366
grub_cmd_xnu_splash (grub_extcmd_context_t ctxt,
1367
int argc, char *args[])
1371
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
1373
if (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set &&
1374
grub_strcmp (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg,
1376
grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH;
1378
grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_CENTER;
1380
err = grub_video_bitmap_load (&grub_xnu_bitmap, args[0]);
1382
grub_xnu_bitmap = 0;
1388
#ifndef GRUB_MACHINE_EMU
1390
grub_cmd_xnu_resume (grub_command_t cmd __attribute__ ((unused)),
1391
int argc, char *args[])
1394
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
1396
return grub_xnu_resume (args[0]);
1404
grub_dl_ref (my_mod);
1412
grub_dl_unref (my_mod);
1416
static grub_command_t cmd_kernel64, cmd_kernel, cmd_mkext, cmd_kext;
1417
static grub_command_t cmd_kextdir, cmd_ramdisk, cmd_resume;
1418
static grub_extcmd_t cmd_splash;
1422
cmd_kernel = grub_register_command ("xnu_kernel", grub_cmd_xnu_kernel, 0,
1423
N_("Load XNU image."));
1424
cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64,
1425
0, N_("Load 64-bit XNU image."));
1426
cmd_mkext = grub_register_command ("xnu_mkext", grub_cmd_xnu_mkext, 0,
1427
N_("Load XNU extension package."));
1428
cmd_kext = grub_register_command ("xnu_kext", grub_cmd_xnu_kext, 0,
1429
N_("Load XNU extension."));
1430
cmd_kextdir = grub_register_command ("xnu_kextdir", grub_cmd_xnu_kextdir,
1431
N_("DIRECTORY [OSBundleRequired]"),
1432
N_("Load XNU extension directory."));
1433
cmd_ramdisk = grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk, 0,
1434
"Load XNU ramdisk. "
1435
"It will be seen as md0.");
1436
cmd_splash = grub_register_extcmd ("xnu_splash",
1437
grub_cmd_xnu_splash, 0, 0,
1438
N_("Load a splash image for XNU."),
1439
xnu_splash_cmd_options);
1441
#ifndef GRUB_MACHINE_EMU
1442
cmd_resume = grub_register_command ("xnu_resume", grub_cmd_xnu_resume,
1443
0, N_("Load XNU hibernate image."));
1446
grub_cpu_xnu_init ();
1453
#ifndef GRUB_MACHINE_EMU
1454
grub_unregister_command (cmd_resume);
1456
grub_unregister_command (cmd_mkext);
1457
grub_unregister_command (cmd_kext);
1458
grub_unregister_command (cmd_kextdir);
1459
grub_unregister_command (cmd_ramdisk);
1460
grub_unregister_command (cmd_kernel);
1461
grub_unregister_extcmd (cmd_splash);
1462
grub_unregister_command (cmd_kernel64);
1464
grub_cpu_xnu_fini ();