]> git.proxmox.com Git - grub2.git/blob - grub-core/loader/xnu.c
* grub-core/efiemu/i386/pc/cfgtables.c
[grub2.git] / grub-core / loader / xnu.c
1 /* xnu.c - load xnu kernel. Thanks to Florian Idelberger for all the
2 time he spent testing this
3 */
4 /*
5 * GRUB -- GRand Unified Bootloader
6 * Copyright (C) 2009 Free Software Foundation, Inc.
7 *
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.
12 *
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.
17 *
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/>.
20 */
21
22 #include <grub/file.h>
23 #include <grub/xnu.h>
24 #include <grub/cpu/xnu.h>
25 #include <grub/mm.h>
26 #include <grub/dl.h>
27 #include <grub/loader.h>
28 #include <grub/machoload.h>
29 #include <grub/macho.h>
30 #include <grub/cpu/macho.h>
31 #include <grub/command.h>
32 #include <grub/misc.h>
33 #include <grub/extcmd.h>
34 #include <grub/env.h>
35 #include <grub/i18n.h>
36
37 #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
38 #include <grub/autoefi.h>
39 #endif
40
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;
45
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;
49
50 static grub_err_t
51 grub_xnu_register_memory (char *prefix, int *suffix,
52 grub_addr_t addr, grub_size_t size);
53 grub_err_t
54 grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target)
55 {
56 grub_err_t err;
57 grub_relocator_chunk_t ch;
58
59 err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch,
60 grub_xnu_heap_target_start
61 + grub_xnu_heap_size, size);
62 if (err)
63 return err;
64
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);
69 return GRUB_ERR_NONE;
70 }
71
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. */
75 grub_err_t
76 grub_xnu_align_heap (int align)
77 {
78 grub_xnu_heap_size
79 = ALIGN_UP (grub_xnu_heap_target_start+ grub_xnu_heap_size, align)
80 - grub_xnu_heap_target_start;
81 return GRUB_ERR_NONE;
82 }
83
84 /* Free subtree pointed by CUR. */
85 void
86 grub_xnu_free_devtree (struct grub_xnu_devtree_key *cur)
87 {
88 struct grub_xnu_devtree_key *d;
89 while (cur)
90 {
91 grub_free (cur->name);
92 if (cur->datasize == -1)
93 grub_xnu_free_devtree (cur->first_child);
94 else if (cur->data)
95 grub_free (cur->data);
96 d = cur->next;
97 grub_free (cur);
98 cur = d;
99 }
100 }
101
102 /* Compute the size of device tree in xnu format. */
103 static grub_size_t
104 grub_xnu_writetree_get_size (struct grub_xnu_devtree_key *start, char *name)
105 {
106 grub_size_t ret;
107 struct grub_xnu_devtree_key *cur;
108
109 /* Key header. */
110 ret = 2 * sizeof (grub_uint32_t);
111
112 /* "name" value. */
113 ret += 32 + sizeof (grub_uint32_t)
114 + grub_strlen (name) + 4
115 - (grub_strlen (name) % 4);
116
117 for (cur = start; cur; cur = cur->next)
118 if (cur->datasize != -1)
119 {
120 int align_overhead;
121
122 align_overhead = 4 - (cur->datasize % 4);
123 if (align_overhead == 4)
124 align_overhead = 0;
125 ret += 32 + sizeof (grub_uint32_t) + cur->datasize + align_overhead;
126 }
127 else
128 ret += grub_xnu_writetree_get_size (cur->first_child, cur->name);
129 return ret;
130 }
131
132 /* Write devtree in XNU format at curptr assuming the head is named NAME.*/
133 static void *
134 grub_xnu_writetree_toheap_real (void *curptr,
135 struct grub_xnu_devtree_key *start, char *name)
136 {
137 struct grub_xnu_devtree_key *cur;
138 int nkeys = 0, nvals = 0;
139 for (cur = start; cur; cur = cur->next)
140 {
141 if (cur->datasize == -1)
142 nkeys++;
143 else
144 nvals++;
145 }
146 /* For the name. */
147 nvals++;
148
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;
153
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));
164
165 /* Then the other values. */
166 for (cur = start; cur; cur = cur->next)
167 if (cur->datasize != -1)
168 {
169 int align_overhead;
170
171 align_overhead = 4 - (cur->datasize % 4);
172 if (align_overhead == 4)
173 align_overhead = 0;
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;
183 }
184
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,
189 cur->first_child,
190 cur->name)))
191 return 0;
192 return curptr;
193 }
194
195 grub_err_t
196 grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size)
197 {
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;
202 grub_err_t err;
203 void *src;
204
205 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
206 if (err)
207 return err;
208
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");
212 if (! chosen)
213 return grub_errno;
214 memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
215 if (! memorymap)
216 return grub_errno;
217
218 driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*driverkey));
219 if (! 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");
231
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),
235 &src, target);
236 if (err)
237 return err;
238
239 /* Put real data in the dummy. */
240 extdesc->addr = *target;
241 extdesc->size = (grub_uint32_t) *size;
242
243 /* Write the tree to heap. */
244 grub_xnu_writetree_toheap_real (src, grub_xnu_devtree_root, "/");
245 return GRUB_ERR_NONE;
246 }
247
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)
251 {
252 struct grub_xnu_devtree_key *cur;
253 for (cur = parent; cur; cur = cur->next)
254 if (grub_strcmp (cur->name, name) == 0)
255 return cur;
256 return 0;
257 }
258
259 struct grub_xnu_devtree_key *
260 grub_xnu_create_key (struct grub_xnu_devtree_key **parent, char *name)
261 {
262 struct grub_xnu_devtree_key *ret;
263 ret = grub_xnu_find_key (*parent, name);
264 if (ret)
265 return ret;
266 ret = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*ret));
267 if (! ret)
268 {
269 grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create key %s", name);
270 return 0;
271 }
272 ret->name = grub_strdup (name);
273 if (! ret->name)
274 {
275 grub_free (ret);
276 grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create key %s", name);
277 return 0;
278 }
279 ret->datasize = -1;
280 ret->next = *parent;
281 *parent = ret;
282 return ret;
283 }
284
285 struct grub_xnu_devtree_key *
286 grub_xnu_create_value (struct grub_xnu_devtree_key **parent, char *name)
287 {
288 struct grub_xnu_devtree_key *ret;
289 ret = grub_xnu_find_key (*parent, name);
290 if (ret)
291 {
292 if (ret->datasize == -1)
293 grub_xnu_free_devtree (ret->first_child);
294 else if (ret->datasize)
295 grub_free (ret->data);
296 ret->datasize = 0;
297 ret->data = 0;
298 return ret;
299 }
300 ret = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*ret));
301 if (! ret)
302 {
303 grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create value %s", name);
304 return 0;
305 }
306 ret->name = grub_strdup (name);
307 if (! ret->name)
308 {
309 grub_free (ret);
310 grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't create value %s", name);
311 return 0;
312 }
313 ret->next = *parent;
314 *parent = ret;
315 return ret;
316 }
317
318 static grub_err_t
319 grub_xnu_unload (void)
320 {
321 grub_cpu_xnu_unload ();
322
323 grub_xnu_free_devtree (grub_xnu_devtree_root);
324 grub_xnu_devtree_root = 0;
325
326 /* Free loaded image. */
327 driversnum = 0;
328 driverspackagenum = 0;
329 grub_relocator_unload (grub_xnu_relocator);
330 grub_xnu_relocator = NULL;
331 grub_xnu_heap_target_start = 0;
332 grub_xnu_heap_size = 0;
333 grub_xnu_unlock ();
334 return GRUB_ERR_NONE;
335 }
336
337 static grub_err_t
338 grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
339 int argc, char *args[])
340 {
341 grub_err_t err;
342 grub_macho_t macho;
343 grub_uint32_t startcode, endcode;
344 int i;
345 char *ptr;
346 void *loadaddr;
347 grub_addr_t loadaddr_target;
348
349 if (argc < 1)
350 return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
351
352 grub_xnu_unload ();
353
354 macho = grub_macho_open (args[0]);
355 if (! macho)
356 return grub_errno;
357 if (! grub_macho_contains_macho32 (macho))
358 {
359 grub_macho_close (macho);
360 return grub_error (GRUB_ERR_BAD_OS,
361 "kernel doesn't contain suitable 32-bit architecture");
362 }
363
364 err = grub_macho_size32 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS);
365 if (err)
366 {
367 grub_macho_close (macho);
368 grub_xnu_unload ();
369 return err;
370 }
371
372 grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
373 (unsigned long) endcode, (unsigned long) startcode);
374
375 grub_xnu_relocator = grub_relocator_new ();
376 if (!grub_xnu_relocator)
377 return grub_errno;
378 grub_xnu_heap_target_start = startcode;
379 err = grub_xnu_heap_malloc (endcode - startcode, &loadaddr,
380 &loadaddr_target);
381
382 if (err)
383 {
384 grub_macho_close (macho);
385 grub_xnu_unload ();
386 return err;
387 }
388
389 /* Load kernel. */
390 err = grub_macho_load32 (macho, (char *) loadaddr - startcode,
391 GRUB_MACHO_NOBSS);
392 if (err)
393 {
394 grub_macho_close (macho);
395 grub_xnu_unload ();
396 return err;
397 }
398
399 grub_xnu_entry_point = grub_macho_get_entry_point32 (macho);
400 if (! grub_xnu_entry_point)
401 {
402 grub_macho_close (macho);
403 grub_xnu_unload ();
404 return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point");
405 }
406
407 grub_macho_close (macho);
408
409 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
410 if (err)
411 {
412 grub_xnu_unload ();
413 return err;
414 }
415
416 /* Copy parameters to kernel command line. */
417 ptr = grub_xnu_cmdline;
418 for (i = 1; i < argc; i++)
419 {
420 if (ptr + grub_strlen (args[i]) + 1
421 >= grub_xnu_cmdline + sizeof (grub_xnu_cmdline))
422 break;
423 grub_memcpy (ptr, args[i], grub_strlen (args[i]));
424 ptr += grub_strlen (args[i]);
425 *ptr = ' ';
426 ptr++;
427 }
428
429 /* Replace last space by '\0'. */
430 if (ptr != grub_xnu_cmdline)
431 *(ptr - 1) = 0;
432
433 #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
434 err = grub_efiemu_autocore ();
435 if (err)
436 return err;
437 #endif
438
439 grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);
440
441 grub_xnu_lock ();
442 grub_xnu_is_64bit = 0;
443
444 return 0;
445 }
446
447 static grub_err_t
448 grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
449 int argc, char *args[])
450 {
451 grub_err_t err;
452 grub_macho_t macho;
453 grub_uint64_t startcode, endcode;
454 int i;
455 char *ptr;
456 void *loadaddr;
457 grub_addr_t loadaddr_target;
458
459 if (argc < 1)
460 return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
461
462 grub_xnu_unload ();
463
464 macho = grub_macho_open (args[0]);
465 if (! macho)
466 return grub_errno;
467 if (! grub_macho_contains_macho64 (macho))
468 {
469 grub_macho_close (macho);
470 return grub_error (GRUB_ERR_BAD_OS,
471 "kernel doesn't contain suitable 64-bit architecture");
472 }
473
474 err = grub_macho_size64 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS);
475 if (err)
476 {
477 grub_macho_close (macho);
478 grub_xnu_unload ();
479 return err;
480 }
481
482 startcode &= 0x0fffffff;
483 endcode &= 0x0fffffff;
484
485 grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
486 (unsigned long) endcode, (unsigned long) startcode);
487
488 grub_xnu_relocator = grub_relocator_new ();
489 if (!grub_xnu_relocator)
490 return grub_errno;
491 grub_xnu_heap_target_start = startcode;
492 err = grub_xnu_heap_malloc (endcode - startcode, &loadaddr,
493 &loadaddr_target);
494
495 if (err)
496 {
497 grub_macho_close (macho);
498 grub_xnu_unload ();
499 return err;
500 }
501
502 /* Load kernel. */
503 err = grub_macho_load64 (macho, (char *) loadaddr - startcode,
504 GRUB_MACHO_NOBSS);
505 if (err)
506 {
507 grub_macho_close (macho);
508 grub_xnu_unload ();
509 return err;
510 }
511
512 grub_xnu_entry_point = grub_macho_get_entry_point64 (macho) & 0x0fffffff;
513 if (! grub_xnu_entry_point)
514 {
515 grub_macho_close (macho);
516 grub_xnu_unload ();
517 return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point");
518 }
519
520 grub_macho_close (macho);
521
522 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
523 if (err)
524 {
525 grub_xnu_unload ();
526 return err;
527 }
528
529 /* Copy parameters to kernel command line. */
530 ptr = grub_xnu_cmdline;
531 for (i = 1; i < argc; i++)
532 {
533 if (ptr + grub_strlen (args[i]) + 1
534 >= grub_xnu_cmdline + sizeof (grub_xnu_cmdline))
535 break;
536 grub_memcpy (ptr, args[i], grub_strlen (args[i]));
537 ptr += grub_strlen (args[i]);
538 *ptr = ' ';
539 ptr++;
540 }
541
542 /* Replace last space by '\0'. */
543 if (ptr != grub_xnu_cmdline)
544 *(ptr - 1) = 0;
545
546 #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
547 err = grub_efiemu_autocore ();
548 if (err)
549 return err;
550 #endif
551
552 grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);
553
554 grub_xnu_lock ();
555 grub_xnu_is_64bit = 1;
556
557 return 0;
558 }
559
560 /* Register a memory in a memory map under name PREFIXSUFFIX
561 and increment SUFFIX. */
562 static grub_err_t
563 grub_xnu_register_memory (char *prefix, int *suffix,
564 grub_addr_t addr, grub_size_t size)
565 {
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;
570
571 if (! grub_xnu_heap_size)
572 return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
573
574 chosen = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
575 if (! chosen)
576 return grub_errno;
577 memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
578 if (! memorymap)
579 return grub_errno;
580
581 driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*driverkey));
582 if (! driverkey)
583 return grub_error (GRUB_ERR_OUT_OF_MEMORY, "can't register memory");
584 if (suffix)
585 {
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");
589 }
590 else
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;
604 }
605
606 static inline char *
607 get_name_ptr (char *name)
608 {
609 char *p = name, *p2;
610 /* Skip Info.plist. */
611 p2 = grub_strrchr (p, '/');
612 if (!p2)
613 return name;
614 if (p2 == name)
615 return name + 1;
616 p = p2 - 1;
617
618 p2 = grub_strrchr (p, '/');
619 if (!p2)
620 return name;
621 if (p2 == name)
622 return name + 1;
623 if (grub_memcmp (p2, "/Contents/", sizeof ("/Contents/") - 1) != 0)
624 return p2 + 1;
625
626 p = p2 - 1;
627
628 p2 = grub_strrchr (p, '/');
629 if (!p2)
630 return name;
631 return p2 + 1;
632 }
633
634 /* Load .kext. */
635 static grub_err_t
636 grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile)
637 {
638 grub_macho_t macho;
639 grub_err_t err;
640 grub_file_t infoplist;
641 struct grub_xnu_extheader *exthead;
642 int neededspace = sizeof (*exthead);
643 grub_uint8_t *buf;
644 void *buf0;
645 grub_addr_t buf_target;
646 grub_size_t infoplistsize = 0, machosize = 0;
647 char *name, *nameend;
648 int namelen;
649
650 name = get_name_ptr (infoplistname);
651 nameend = grub_strchr (name, '/');
652
653 if (nameend)
654 namelen = nameend - name;
655 else
656 namelen = grub_strlen (name);
657
658 neededspace += namelen + 1;
659
660 if (! grub_xnu_heap_size)
661 return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
662
663 /* Compute the needed space. */
664 if (binaryfile)
665 {
666 macho = grub_macho_file (binaryfile);
667 if (! macho || ! grub_macho_contains_macho32 (macho))
668 {
669 if (macho)
670 grub_macho_close (macho);
671 return grub_error (GRUB_ERR_BAD_OS,
672 "extension doesn't contain suitable architecture");
673 }
674 if (grub_xnu_is_64bit)
675 machosize = grub_macho_filesize64 (macho);
676 else
677 machosize = grub_macho_filesize32 (macho);
678 neededspace += machosize;
679 }
680 else
681 macho = 0;
682
683 if (infoplistname)
684 infoplist = grub_file_open (infoplistname);
685 else
686 infoplist = 0;
687 grub_errno = GRUB_ERR_NONE;
688 if (infoplist)
689 {
690 infoplistsize = grub_file_size (infoplist);
691 neededspace += infoplistsize + 1;
692 }
693 else
694 infoplistsize = 0;
695
696 /* Allocate the space. */
697 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
698 if (err)
699 return err;
700 err = grub_xnu_heap_malloc (neededspace, &buf0, &buf_target);
701 if (err)
702 return err;
703 buf = buf0;
704
705 exthead = (struct grub_xnu_extheader *) buf;
706 grub_memset (exthead, 0, sizeof (*exthead));
707 buf += sizeof (*exthead);
708
709 /* Load the binary. */
710 if (macho)
711 {
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);
716 else
717 err = grub_macho_readfile32 (macho, buf);
718 if (err)
719 {
720 grub_macho_close (macho);
721 return err;
722 }
723 grub_macho_close (macho);
724 buf += machosize;
725 }
726 grub_errno = GRUB_ERR_NONE;
727
728 /* Load the plist. */
729 if (infoplist)
730 {
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))
735 {
736 grub_file_close (infoplist);
737 grub_error_push ();
738 return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s: ",
739 infoplistname);
740 }
741 grub_file_close (infoplist);
742 buf[infoplistsize] = 0;
743 buf += infoplistsize + 1;
744 }
745 grub_errno = GRUB_ERR_NONE;
746
747 exthead->nameaddr = (buf - (grub_uint8_t *) buf0) + buf_target;
748 exthead->namesize = namelen + 1;
749 grub_memcpy (buf, name, namelen);
750 buf[namelen] = 0;
751 buf += namelen + 1;
752
753 /* Announce to kernel */
754 return grub_xnu_register_memory ("Driver-", &driversnum, buf_target,
755 neededspace);
756 }
757
758 /* Load mkext. */
759 static grub_err_t
760 grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)),
761 int argc, char *args[])
762 {
763 grub_file_t file;
764 void *loadto;
765 grub_addr_t loadto_target;
766 grub_err_t err;
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;
771 int narchs, i;
772
773 if (argc != 1)
774 return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
775
776 if (! grub_xnu_heap_size)
777 return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
778
779 file = grub_file_open (args[0]);
780 if (! file)
781 return grub_error (GRUB_ERR_FILE_NOT_FOUND,
782 "couldn't load driver package");
783
784 /* Sometimes caches are fat binary. Errgh. */
785 if (grub_file_read (file, &head, sizeof (head))
786 != (grub_ssize_t) (sizeof (head)))
787 {
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);
791 grub_error_push ();
792 return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]);
793 }
794
795 /* Find the corresponding architecture. */
796 if (grub_be_to_cpu32 (head.magic) == GRUB_MACHO_FAT_MAGIC)
797 {
798 narchs = grub_be_to_cpu32 (head.nfat_arch);
799 archs = grub_malloc (sizeof (struct grub_macho_fat_arch) * narchs);
800 if (! archs)
801 {
802 grub_file_close (file);
803 grub_error_push ();
804 return grub_error (GRUB_ERR_OUT_OF_MEMORY,
805 "couldn't read file %s", args[0]);
806
807 }
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)
811 {
812 grub_free (archs);
813 grub_error_push ();
814 return grub_error (GRUB_ERR_READ_ERROR, "cannot read fat header");
815 }
816 for (i = 0; i < narchs; i++)
817 {
818 if (!grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST32
819 (grub_be_to_cpu32 (archs[i].cputype)))
820 {
821 readoff = grub_be_to_cpu32 (archs[i].offset);
822 readlen = grub_be_to_cpu32 (archs[i].size);
823 }
824 if (grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST64
825 (grub_be_to_cpu32 (archs[i].cputype)))
826 {
827 readoff = grub_be_to_cpu32 (archs[i].offset);
828 readlen = grub_be_to_cpu32 (archs[i].size);
829 }
830 }
831 grub_free (archs);
832 }
833 else
834 {
835 /* It's a flat file. Some sane people still exist. */
836 readoff = 0;
837 readlen = grub_file_size (file);
838 }
839
840 if (readlen == -1)
841 {
842 grub_file_close (file);
843 return grub_error (GRUB_ERR_BAD_OS, "no suitable architecture is found");
844 }
845
846 /* Allocate space. */
847 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
848 if (err)
849 {
850 grub_file_close (file);
851 return err;
852 }
853
854 err = grub_xnu_heap_malloc (readlen, &loadto, &loadto_target);
855 if (err)
856 {
857 grub_file_close (file);
858 return err;
859 }
860
861 /* Read the file. */
862 grub_file_seek (file, readoff);
863 if (grub_file_read (file, loadto, readlen) != (grub_ssize_t) (readlen))
864 {
865 grub_file_close (file);
866 grub_error_push ();
867 return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]);
868 }
869 grub_file_close (file);
870
871 /* Pass it to kernel. */
872 return grub_xnu_register_memory ("DriversPackage-", &driverspackagenum,
873 loadto_target, readlen);
874 }
875
876 static grub_err_t
877 grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)),
878 int argc, char *args[])
879 {
880 grub_file_t file;
881 void *loadto;
882 grub_addr_t loadto_target;
883 grub_err_t err;
884 grub_size_t size;
885
886 if (argc != 1)
887 return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
888
889 if (! grub_xnu_heap_size)
890 return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
891
892 file = grub_file_open (args[0]);
893 if (! file)
894 return grub_error (GRUB_ERR_FILE_NOT_FOUND,
895 "couldn't load ramdisk");
896
897 err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
898 if (err)
899 return err;
900
901 size = grub_file_size (file);
902
903 err = grub_xnu_heap_malloc (size, &loadto, &loadto_target);
904 if (err)
905 return err;
906 if (grub_file_read (file, loadto, size)
907 != (grub_ssize_t) (size))
908 {
909 grub_file_close (file);
910 grub_error_push ();
911 return grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", args[0]);
912 }
913 return grub_xnu_register_memory ("RAMDisk", 0, loadto_target, size);
914 }
915
916 /* Returns true if the kext should be loaded according to plist
917 and osbundlereq. Also fill BINNAME. */
918 static int
919 grub_xnu_check_os_bundle_required (char *plistname, char *osbundlereq,
920 char **binname)
921 {
922 grub_file_t file;
923 char *buf = 0, *tagstart = 0, *ptr1 = 0, *keyptr = 0;
924 char *stringptr = 0, *ptr2 = 0;
925 grub_size_t size;
926 int depth = 0;
927 int ret;
928 int osbundlekeyfound = 0, binnamekeyfound = 0;
929 if (binname)
930 *binname = 0;
931
932 file = grub_file_open (plistname);
933 if (! file)
934 {
935 grub_file_close (file);
936 grub_error_push ();
937 grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", plistname);
938 return 0;
939 }
940
941 size = grub_file_size (file);
942 buf = grub_malloc (size);
943 if (! buf)
944 {
945 grub_file_close (file);
946 grub_error_push ();
947 grub_error (GRUB_ERR_OUT_OF_MEMORY, "couldn't read file %s", plistname);
948 return 0;
949 }
950 if (grub_file_read (file, buf, size) != (grub_ssize_t) (size))
951 {
952 grub_file_close (file);
953 grub_error_push ();
954 grub_error (GRUB_ERR_BAD_OS, "couldn't read file %s", plistname);
955 return 0;
956 }
957 grub_file_close (file);
958
959 /* Set the return value for the case when no OSBundleRequired tag is found. */
960 if (osbundlereq)
961 ret = grub_strword (osbundlereq, "all") || grub_strword (osbundlereq, "-");
962 else
963 ret = 1;
964
965 /* Parse plist. It's quite dirty and inextensible but does its job. */
966 for (ptr1 = buf; ptr1 < buf + size; ptr1++)
967 switch (*ptr1)
968 {
969 case '<':
970 tagstart = ptr1;
971 *ptr1 = 0;
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)
977 binnamekeyfound = 1;
978 if (stringptr && osbundlekeyfound && osbundlereq && depth == 4)
979 {
980 for (ptr2 = stringptr; *ptr2; ptr2++)
981 *ptr2 = grub_tolower (*ptr2);
982 ret = grub_strword (osbundlereq, stringptr)
983 || grub_strword (osbundlereq, "all");
984 }
985 if (stringptr && binnamekeyfound && binname && depth == 4)
986 {
987 if (*binname)
988 grub_free (*binname);
989 *binname = grub_strdup (stringptr);
990 }
991
992 *ptr1 = '<';
993 keyptr = 0;
994 stringptr = 0;
995 break;
996 case '>':
997 if (! tagstart)
998 {
999 grub_free (buf);
1000 grub_error (GRUB_ERR_BAD_OS, "can't parse %s", plistname);
1001 return 0;
1002 }
1003 *ptr1 = 0;
1004 if (tagstart[1] == '?' || ptr1[-1] == '/')
1005 {
1006 osbundlekeyfound = 0;
1007 *ptr1 = '>';
1008 break;
1009 }
1010 if (depth == 3 && grub_strcmp (tagstart + 1, "key") == 0)
1011 keyptr = ptr1 + 1;
1012 if (depth == 3 && grub_strcmp (tagstart + 1, "string") == 0)
1013 stringptr = ptr1 + 1;
1014 else if (grub_strcmp (tagstart + 1, "/key") != 0)
1015 {
1016 osbundlekeyfound = 0;
1017 binnamekeyfound = 0;
1018 }
1019 *ptr1 = '>';
1020
1021 if (tagstart[1] == '/')
1022 depth--;
1023 else
1024 depth++;
1025 break;
1026 }
1027 grub_free (buf);
1028
1029 return ret;
1030 }
1031
1032 /* Load all loadable kexts placed under DIRNAME and matching OSBUNDLEREQUIRED */
1033 grub_err_t
1034 grub_xnu_scan_dir_for_kexts (char *dirname, char *osbundlerequired,
1035 int maxrecursion)
1036 {
1037 grub_device_t dev;
1038 char *device_name;
1039 grub_fs_t fs;
1040 const char *path;
1041
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)
1045 {
1046 char *newdirname;
1047 if (! info->dir)
1048 return 0;
1049 if (filename[0] == '.')
1050 return 0;
1051
1052 if (grub_strlen (filename) < 5 ||
1053 grub_memcmp (filename + grub_strlen (filename) - 5, ".kext", 5) != 0)
1054 return 0;
1055
1056 newdirname
1057 = grub_malloc (grub_strlen (dirname) + grub_strlen (filename) + 2);
1058
1059 /* It's a .kext. Try to load it. */
1060 if (newdirname)
1061 {
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,
1067 maxrecursion);
1068 if (grub_errno == GRUB_ERR_BAD_OS)
1069 grub_errno = GRUB_ERR_NONE;
1070 grub_free (newdirname);
1071 }
1072 return 0;
1073 }
1074
1075 if (! grub_xnu_heap_size)
1076 return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
1077
1078 device_name = grub_file_get_device_name (dirname);
1079 dev = grub_device_open (device_name);
1080 if (dev)
1081 {
1082 fs = grub_fs_probe (dev);
1083 path = grub_strchr (dirname, ')');
1084 if (! path)
1085 path = dirname;
1086 else
1087 path++;
1088
1089 if (fs)
1090 (fs->dir) (dev, path, load_hook);
1091 grub_device_close (dev);
1092 }
1093 grub_free (device_name);
1094
1095 return GRUB_ERR_NONE;
1096 }
1097
1098 /* Load extension DIRNAME. (extensions are directories in xnu) */
1099 grub_err_t
1100 grub_xnu_load_kext_from_dir (char *dirname, char *osbundlerequired,
1101 int maxrecursion)
1102 {
1103 grub_device_t dev;
1104 char *plistname = 0;
1105 char *newdirname;
1106 char *newpath;
1107 char *device_name;
1108 grub_fs_t fs;
1109 const char *path;
1110 char *binsuffix;
1111 int usemacos = 0;
1112 grub_file_t binfile;
1113
1114 auto int load_hook (const char *filename,
1115 const struct grub_dirhook_info *info);
1116
1117 int load_hook (const char *filename, const struct grub_dirhook_info *info)
1118 {
1119 if (grub_strlen (filename) > 15)
1120 return 0;
1121 grub_strcpy (newdirname + grub_strlen (dirname) + 1, filename);
1122
1123 /* If the kext contains directory "Contents" all real stuff is in
1124 this directory. */
1125 if (info->dir && grub_strcasecmp (filename, "Contents") == 0)
1126 grub_xnu_load_kext_from_dir (newdirname, osbundlerequired,
1127 maxrecursion - 1);
1128
1129 /* Directory "Plugins" contains nested kexts. */
1130 if (info->dir && grub_strcasecmp (filename, "Plugins") == 0)
1131 grub_xnu_scan_dir_for_kexts (newdirname, osbundlerequired,
1132 maxrecursion - 1);
1133
1134 /* Directory "MacOS" contains executable, otherwise executable is
1135 on the top. */
1136 if (info->dir && grub_strcasecmp (filename, "MacOS") == 0)
1137 usemacos = 1;
1138
1139 /* Info.plist is the file which governs our future actions. */
1140 if (! info->dir && grub_strcasecmp (filename, "Info.plist") == 0
1141 && ! plistname)
1142 plistname = grub_strdup (newdirname);
1143 return 0;
1144 }
1145
1146 newdirname = grub_malloc (grub_strlen (dirname) + 20);
1147 if (! newdirname)
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);
1154 if (dev)
1155 {
1156 fs = grub_fs_probe (dev);
1157 path = grub_strchr (dirname, ')');
1158 if (! path)
1159 path = dirname;
1160 else
1161 path++;
1162
1163 newpath = grub_strchr (newdirname, ')');
1164 if (! newpath)
1165 newpath = newdirname;
1166 else
1167 newpath++;
1168
1169 /* Look at the directory. */
1170 if (fs)
1171 (fs->dir) (dev, path, load_hook);
1172
1173 if (plistname && grub_xnu_check_os_bundle_required
1174 (plistname, osbundlerequired, &binsuffix))
1175 {
1176 if (binsuffix)
1177 {
1178 /* Open the binary. */
1179 char *binname = grub_malloc (grub_strlen (dirname)
1180 + grub_strlen (binsuffix)
1181 + sizeof ("/MacOS/"));
1182 grub_strcpy (binname, dirname);
1183 if (usemacos)
1184 grub_strcpy (binname + grub_strlen (binname), "/MacOS/");
1185 else
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);
1190 if (! binfile)
1191 grub_errno = GRUB_ERR_NONE;
1192
1193 /* Load the extension. */
1194 grub_xnu_load_driver (plistname, binfile);
1195 grub_free (binname);
1196 grub_free (binsuffix);
1197 }
1198 else
1199 {
1200 grub_dprintf ("xnu", "%s:0\n", plistname);
1201 grub_xnu_load_driver (plistname, 0);
1202 }
1203 }
1204 grub_free (plistname);
1205 grub_device_close (dev);
1206 }
1207 grub_free (device_name);
1208
1209 return GRUB_ERR_NONE;
1210 }
1211
1212
1213 static int locked=0;
1214 static grub_dl_t my_mod;
1215
1216 /* Load the kext. */
1217 static grub_err_t
1218 grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)),
1219 int argc, char *args[])
1220 {
1221 grub_file_t binfile = 0;
1222
1223 if (! grub_xnu_heap_size)
1224 return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
1225
1226 if (argc == 2)
1227 {
1228 /* User explicitly specified plist and binary. */
1229 if (grub_strcmp (args[1], "-") != 0)
1230 {
1231 binfile = grub_file_open (args[1]);
1232 if (! binfile)
1233 {
1234 grub_error (GRUB_ERR_BAD_OS, "can't open file");
1235 return GRUB_ERR_NONE;
1236 }
1237 }
1238 return grub_xnu_load_driver (grub_strcmp (args[0], "-") ? args[0] : 0,
1239 binfile);
1240 }
1241
1242 /* load kext normally. */
1243 if (argc == 1)
1244 return grub_xnu_load_kext_from_dir (args[0], 0, 10);
1245
1246 return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
1247 }
1248
1249 /* Load a directory containing kexts. */
1250 static grub_err_t
1251 grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ ((unused)),
1252 int argc, char *args[])
1253 {
1254 if (argc != 1 && argc != 2)
1255 return grub_error (GRUB_ERR_BAD_ARGUMENT, "directory name required");
1256
1257 if (! grub_xnu_heap_size)
1258 return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
1259
1260 if (argc == 1)
1261 return grub_xnu_scan_dir_for_kexts (args[0],
1262 "console,root,local-root,network-root",
1263 10);
1264 else
1265 {
1266 char *osbundlerequired = grub_strdup (args[1]), *ptr;
1267 grub_err_t err;
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);
1275 return err;
1276 }
1277 }
1278
1279 static inline int
1280 hextoval (char c)
1281 {
1282 if (c >= '0' && c <= '9')
1283 return c - '0';
1284 if (c >= 'a' && c <= 'z')
1285 return c - 'a' + 10;
1286 if (c >= 'A' && c <= 'Z')
1287 return c - 'A' + 10;
1288 return 0;
1289 }
1290
1291 static inline void
1292 unescape (char *name, char *curdot, char *nextdot, int *len)
1293 {
1294 char *ptr, *dptr;
1295 dptr = name;
1296 for (ptr = curdot; ptr < nextdot;)
1297 if (ptr + 2 < nextdot && *ptr == '%')
1298 {
1299 *dptr = (hextoval (ptr[1]) << 4) | (hextoval (ptr[2]));
1300 ptr += 3;
1301 dptr++;
1302 }
1303 else
1304 {
1305 *dptr = *ptr;
1306 ptr++;
1307 dptr++;
1308 }
1309 *len = dptr - name;
1310 }
1311
1312 grub_err_t
1313 grub_xnu_fill_devicetree (void)
1314 {
1315 auto int iterate_env (struct grub_env_var *var);
1316 int iterate_env (struct grub_env_var *var)
1317 {
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;
1322 int len;
1323
1324 if (grub_memcmp (var->name, "XNU.DeviceTree.",
1325 sizeof ("XNU.DeviceTree.") - 1) != 0)
1326 return 0;
1327
1328 curdot = var->name + sizeof ("XNU.DeviceTree.") - 1;
1329 nextdot = grub_strchr (curdot, '.');
1330 if (nextdot)
1331 nextdot++;
1332 while (nextdot)
1333 {
1334 name = grub_realloc (name, nextdot - curdot + 1);
1335
1336 if (!name)
1337 return 1;
1338
1339 unescape (name, curdot, nextdot, &len);
1340 name[len - 1] = 0;
1341
1342 curkey = &(grub_xnu_create_key (curkey, name)->first_child);
1343
1344 curdot = nextdot;
1345 nextdot = grub_strchr (nextdot, '.');
1346 if (nextdot)
1347 nextdot++;
1348 }
1349
1350 nextdot = curdot + grub_strlen (curdot) + 1;
1351
1352 name = grub_realloc (name, nextdot - curdot + 1);
1353
1354 if (!name)
1355 return 1;
1356
1357 unescape (name, curdot, nextdot, &len);
1358 name[len] = 0;
1359
1360 curvalue = grub_xnu_create_value (curkey, name);
1361 grub_free (name);
1362
1363 data = grub_malloc (grub_strlen (var->value) + 1);
1364 if (!data)
1365 return 1;
1366
1367 unescape (data, var->value, var->value + grub_strlen (var->value),
1368 &len);
1369 curvalue->datasize = len;
1370 curvalue->data = data;
1371
1372 return 0;
1373 }
1374
1375 grub_env_iterate (iterate_env);
1376
1377 return grub_errno;
1378 }
1379
1380 struct grub_video_bitmap *grub_xnu_bitmap = 0;
1381 grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode;
1382
1383 /* Option array indices. */
1384 #define XNU_SPLASH_CMD_ARGINDEX_MODE 0
1385
1386 static const struct grub_arg_option xnu_splash_cmd_options[] =
1387 {
1388 {"mode", 'm', 0, "Background image mode.", "stretch|normal",
1389 ARG_TYPE_STRING},
1390 {0, 0, 0, 0, 0, 0}
1391 };
1392
1393 static grub_err_t
1394 grub_cmd_xnu_splash (grub_extcmd_context_t ctxt,
1395 int argc, char *args[])
1396 {
1397 grub_err_t err;
1398 if (argc != 1)
1399 return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
1400
1401 if (! grub_xnu_heap_size)
1402 return grub_error (GRUB_ERR_BAD_OS, "no xnu kernel loaded");
1403
1404 if (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set &&
1405 grub_strcmp (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg,
1406 "stretch") == 0)
1407 grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH;
1408 else
1409 grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_CENTER;
1410
1411 err = grub_video_bitmap_load (&grub_xnu_bitmap, args[0]);
1412 if (err)
1413 grub_xnu_bitmap = 0;
1414
1415 return err;
1416 }
1417
1418
1419 #ifndef GRUB_MACHINE_EMU
1420 static grub_err_t
1421 grub_cmd_xnu_resume (grub_command_t cmd __attribute__ ((unused)),
1422 int argc, char *args[])
1423 {
1424 if (argc != 1)
1425 return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
1426
1427 return grub_xnu_resume (args[0]);
1428 }
1429 #endif
1430
1431 void
1432 grub_xnu_lock (void)
1433 {
1434 if (!locked)
1435 grub_dl_ref (my_mod);
1436 locked = 1;
1437 }
1438
1439 void
1440 grub_xnu_unlock (void)
1441 {
1442 if (locked)
1443 grub_dl_unref (my_mod);
1444 locked = 0;
1445 }
1446
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;
1450
1451 GRUB_MOD_INIT(xnu)
1452 {
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);
1471
1472 #ifndef GRUB_MACHINE_EMU
1473 cmd_resume = grub_register_command ("xnu_resume", grub_cmd_xnu_resume,
1474 0, N_("Load XNU hibernate image."));
1475 #endif
1476
1477 grub_cpu_xnu_init ();
1478
1479 my_mod = mod;
1480 }
1481
1482 GRUB_MOD_FINI(xnu)
1483 {
1484 #ifndef GRUB_MACHINE_EMU
1485 grub_unregister_command (cmd_resume);
1486 #endif
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);
1494
1495 grub_cpu_xnu_fini ();
1496 }