xnu.c 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534
  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. #include <grub/file.h>
  22. #include <grub/xnu.h>
  23. #include <grub/cpu/xnu.h>
  24. #include <grub/mm.h>
  25. #include <grub/dl.h>
  26. #include <grub/loader.h>
  27. #include <grub/machoload.h>
  28. #include <grub/macho.h>
  29. #include <grub/cpu/macho.h>
  30. #include <grub/command.h>
  31. #include <grub/misc.h>
  32. #include <grub/extcmd.h>
  33. #include <grub/env.h>
  34. #include <grub/i18n.h>
  35. #include <grub/verify.h>
  36. GRUB_MOD_LICENSE ("GPLv3+");
  37. #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
  38. #include <grub/autoefi.h>
  39. #endif
  40. struct grub_xnu_devtree_key *grub_xnu_devtree_root = 0;
  41. static int driverspackagenum = 0;
  42. static int driversnum = 0;
  43. int grub_xnu_is_64bit = 0;
  44. int grub_xnu_darwin_version = 0;
  45. grub_addr_t grub_xnu_heap_target_start = 0;
  46. grub_size_t grub_xnu_heap_size = 0;
  47. struct grub_relocator *grub_xnu_relocator;
  48. static grub_err_t
  49. grub_xnu_register_memory (const char *prefix, int *suffix,
  50. grub_addr_t addr, grub_size_t size);
  51. grub_err_t
  52. grub_xnu_heap_malloc (int size, void **src, grub_addr_t *target)
  53. {
  54. grub_err_t err;
  55. grub_relocator_chunk_t ch;
  56. err = grub_relocator_alloc_chunk_addr (grub_xnu_relocator, &ch,
  57. grub_xnu_heap_target_start
  58. + grub_xnu_heap_size, size);
  59. if (err)
  60. return err;
  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);
  65. return GRUB_ERR_NONE;
  66. }
  67. /* Make sure next block of the heap will be aligned.
  68. Please notice: aligned are pointers AFTER relocation
  69. and not the current ones. */
  70. grub_err_t
  71. grub_xnu_align_heap (int align)
  72. {
  73. grub_xnu_heap_size
  74. = ALIGN_UP (grub_xnu_heap_target_start+ grub_xnu_heap_size, align)
  75. - grub_xnu_heap_target_start;
  76. return GRUB_ERR_NONE;
  77. }
  78. /* Free subtree pointed by CUR. */
  79. void
  80. grub_xnu_free_devtree (struct grub_xnu_devtree_key *cur)
  81. {
  82. struct grub_xnu_devtree_key *d;
  83. while (cur)
  84. {
  85. grub_free (cur->name);
  86. if (cur->datasize == -1)
  87. grub_xnu_free_devtree (cur->first_child);
  88. else if (cur->data)
  89. grub_free (cur->data);
  90. d = cur->next;
  91. grub_free (cur);
  92. cur = d;
  93. }
  94. }
  95. /* Compute the size of device tree in xnu format. */
  96. static grub_size_t
  97. grub_xnu_writetree_get_size (struct grub_xnu_devtree_key *start,
  98. const char *name)
  99. {
  100. grub_size_t ret;
  101. struct grub_xnu_devtree_key *cur;
  102. /* Key header. */
  103. ret = 2 * sizeof (grub_uint32_t);
  104. /* "name" value. */
  105. ret += 32 + sizeof (grub_uint32_t)
  106. + grub_strlen (name) + 4
  107. - (grub_strlen (name) % 4);
  108. for (cur = start; cur; cur = cur->next)
  109. if (cur->datasize != -1)
  110. {
  111. int align_overhead;
  112. align_overhead = 4 - (cur->datasize % 4);
  113. if (align_overhead == 4)
  114. align_overhead = 0;
  115. ret += 32 + sizeof (grub_uint32_t) + cur->datasize + align_overhead;
  116. }
  117. else
  118. ret += grub_xnu_writetree_get_size (cur->first_child, cur->name);
  119. return ret;
  120. }
  121. /* Write devtree in XNU format at curptr assuming the head is named NAME.*/
  122. static void *
  123. grub_xnu_writetree_toheap_real (void *curptr,
  124. struct grub_xnu_devtree_key *start,
  125. const char *name)
  126. {
  127. struct grub_xnu_devtree_key *cur;
  128. int nkeys = 0, nvals = 0;
  129. for (cur = start; cur; cur = cur->next)
  130. {
  131. if (cur->datasize == -1)
  132. nkeys++;
  133. else
  134. nvals++;
  135. }
  136. /* For the name. */
  137. nvals++;
  138. *((grub_uint32_t *) curptr) = nvals;
  139. curptr = ((grub_uint32_t *) curptr) + 1;
  140. *((grub_uint32_t *) curptr) = nkeys;
  141. curptr = ((grub_uint32_t *) curptr) + 1;
  142. /* First comes "name" value. */
  143. grub_memset (curptr, 0, 32);
  144. grub_memcpy (curptr, "name", 4);
  145. curptr = ((grub_uint8_t *) curptr) + 32;
  146. *((grub_uint32_t *)curptr) = grub_strlen (name) + 1;
  147. curptr = ((grub_uint32_t *) curptr) + 1;
  148. grub_memcpy (curptr, name, grub_strlen (name));
  149. curptr = ((grub_uint8_t *) curptr) + grub_strlen (name);
  150. grub_memset (curptr, 0, 4 - (grub_strlen (name) % 4));
  151. curptr = ((grub_uint8_t *) curptr) + (4 - (grub_strlen (name) % 4));
  152. /* Then the other values. */
  153. for (cur = start; cur; cur = cur->next)
  154. if (cur->datasize != -1)
  155. {
  156. int align_overhead;
  157. align_overhead = 4 - (cur->datasize % 4);
  158. if (align_overhead == 4)
  159. align_overhead = 0;
  160. grub_memset (curptr, 0, 32);
  161. grub_strncpy (curptr, cur->name, 31);
  162. curptr = ((grub_uint8_t *) curptr) + 32;
  163. *((grub_uint32_t *) curptr) = cur->datasize;
  164. curptr = ((grub_uint32_t *) curptr) + 1;
  165. grub_memcpy (curptr, cur->data, cur->datasize);
  166. curptr = ((grub_uint8_t *) curptr) + cur->datasize;
  167. grub_memset (curptr, 0, align_overhead);
  168. curptr = ((grub_uint8_t *) curptr) + align_overhead;
  169. }
  170. /* And then the keys. Recursively use this function. */
  171. for (cur = start; cur; cur = cur->next)
  172. if (cur->datasize == -1)
  173. {
  174. curptr = grub_xnu_writetree_toheap_real (curptr,
  175. cur->first_child,
  176. cur->name);
  177. if (!curptr)
  178. return 0;
  179. }
  180. return curptr;
  181. }
  182. grub_err_t
  183. grub_xnu_writetree_toheap (grub_addr_t *target, grub_size_t *size)
  184. {
  185. struct grub_xnu_devtree_key *chosen;
  186. struct grub_xnu_devtree_key *memorymap;
  187. struct grub_xnu_devtree_key *driverkey;
  188. struct grub_xnu_extdesc *extdesc;
  189. grub_err_t err;
  190. void *src;
  191. err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
  192. if (err)
  193. return err;
  194. /* Device tree itself is in the memory map of device tree. */
  195. /* Create a dummy value in memory-map. */
  196. chosen = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
  197. if (! chosen)
  198. return grub_errno;
  199. memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
  200. if (! memorymap)
  201. return grub_errno;
  202. driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*driverkey));
  203. if (! driverkey)
  204. return grub_errno;
  205. driverkey->name = grub_strdup ("DeviceTree");
  206. if (! driverkey->name)
  207. return grub_errno;
  208. driverkey->datasize = sizeof (*extdesc);
  209. driverkey->next = memorymap->first_child;
  210. memorymap->first_child = driverkey;
  211. driverkey->data = extdesc
  212. = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc));
  213. if (! driverkey->data)
  214. return grub_errno;
  215. /* Allocate the space based on the size with dummy value. */
  216. *size = grub_xnu_writetree_get_size (grub_xnu_devtree_root, "/");
  217. err = grub_xnu_heap_malloc (ALIGN_UP (*size + 1, GRUB_XNU_PAGESIZE),
  218. &src, target);
  219. if (err)
  220. return err;
  221. /* Put real data in the dummy. */
  222. extdesc->addr = *target;
  223. extdesc->size = (grub_uint32_t) *size;
  224. /* Write the tree to heap. */
  225. grub_xnu_writetree_toheap_real (src, grub_xnu_devtree_root, "/");
  226. return GRUB_ERR_NONE;
  227. }
  228. /* Find a key or value in parent key. */
  229. struct grub_xnu_devtree_key *
  230. grub_xnu_find_key (struct grub_xnu_devtree_key *parent, const char *name)
  231. {
  232. struct grub_xnu_devtree_key *cur;
  233. for (cur = parent; cur; cur = cur->next)
  234. if (grub_strcmp (cur->name, name) == 0)
  235. return cur;
  236. return 0;
  237. }
  238. struct grub_xnu_devtree_key *
  239. grub_xnu_create_key (struct grub_xnu_devtree_key **parent, const char *name)
  240. {
  241. struct grub_xnu_devtree_key *ret;
  242. ret = grub_xnu_find_key (*parent, name);
  243. if (ret)
  244. return ret;
  245. ret = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*ret));
  246. if (! ret)
  247. return 0;
  248. ret->name = grub_strdup (name);
  249. if (! ret->name)
  250. {
  251. grub_free (ret);
  252. return 0;
  253. }
  254. ret->datasize = -1;
  255. ret->next = *parent;
  256. *parent = ret;
  257. return ret;
  258. }
  259. struct grub_xnu_devtree_key *
  260. grub_xnu_create_value (struct grub_xnu_devtree_key **parent, const char *name)
  261. {
  262. struct grub_xnu_devtree_key *ret;
  263. ret = grub_xnu_find_key (*parent, name);
  264. if (ret)
  265. {
  266. if (ret->datasize == -1)
  267. grub_xnu_free_devtree (ret->first_child);
  268. else if (ret->datasize)
  269. grub_free (ret->data);
  270. ret->datasize = 0;
  271. ret->data = 0;
  272. return ret;
  273. }
  274. ret = (struct grub_xnu_devtree_key *) grub_zalloc (sizeof (*ret));
  275. if (! ret)
  276. return 0;
  277. ret->name = grub_strdup (name);
  278. if (! ret->name)
  279. {
  280. grub_free (ret);
  281. return 0;
  282. }
  283. ret->next = *parent;
  284. *parent = ret;
  285. return ret;
  286. }
  287. static grub_err_t
  288. grub_xnu_unload (void)
  289. {
  290. grub_cpu_xnu_unload ();
  291. grub_xnu_free_devtree (grub_xnu_devtree_root);
  292. grub_xnu_devtree_root = 0;
  293. /* Free loaded image. */
  294. driversnum = 0;
  295. driverspackagenum = 0;
  296. grub_relocator_unload (grub_xnu_relocator);
  297. grub_xnu_relocator = NULL;
  298. grub_xnu_heap_target_start = 0;
  299. grub_xnu_heap_size = 0;
  300. grub_xnu_unlock ();
  301. return GRUB_ERR_NONE;
  302. }
  303. static grub_err_t
  304. grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
  305. int argc, char *args[])
  306. {
  307. grub_err_t err;
  308. grub_macho_t macho;
  309. grub_uint32_t startcode, endcode;
  310. int i;
  311. char *ptr;
  312. void *loadaddr;
  313. grub_addr_t loadaddr_target;
  314. if (argc < 1)
  315. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
  316. grub_xnu_unload ();
  317. macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, 0);
  318. if (! macho)
  319. return grub_errno;
  320. err = grub_macho_size32 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS,
  321. args[0]);
  322. if (err)
  323. {
  324. grub_macho_close (macho);
  325. grub_xnu_unload ();
  326. return err;
  327. }
  328. grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
  329. (unsigned long) endcode, (unsigned long) startcode);
  330. grub_xnu_relocator = grub_relocator_new ();
  331. if (!grub_xnu_relocator)
  332. return grub_errno;
  333. grub_xnu_heap_target_start = startcode;
  334. err = grub_xnu_heap_malloc (endcode - startcode, &loadaddr,
  335. &loadaddr_target);
  336. if (err)
  337. {
  338. grub_macho_close (macho);
  339. grub_xnu_unload ();
  340. return err;
  341. }
  342. /* Load kernel. */
  343. err = grub_macho_load32 (macho, args[0], (char *) loadaddr - startcode,
  344. GRUB_MACHO_NOBSS, &grub_xnu_darwin_version);
  345. if (err)
  346. {
  347. grub_macho_close (macho);
  348. grub_xnu_unload ();
  349. return err;
  350. }
  351. grub_xnu_entry_point = grub_macho_get_entry_point32 (macho, args[0]);
  352. if (! grub_xnu_entry_point)
  353. {
  354. grub_macho_close (macho);
  355. grub_xnu_unload ();
  356. return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point");
  357. }
  358. grub_macho_close (macho);
  359. err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
  360. if (err)
  361. {
  362. grub_xnu_unload ();
  363. return err;
  364. }
  365. /* Copy parameters to kernel command line. */
  366. ptr = grub_xnu_cmdline;
  367. for (i = 1; i < argc; i++)
  368. {
  369. if (ptr + grub_strlen (args[i]) + 1
  370. >= grub_xnu_cmdline + sizeof (grub_xnu_cmdline))
  371. break;
  372. grub_memcpy (ptr, args[i], grub_strlen (args[i]));
  373. ptr += grub_strlen (args[i]);
  374. *ptr = ' ';
  375. ptr++;
  376. }
  377. /* Replace last space by '\0'. */
  378. if (ptr != grub_xnu_cmdline)
  379. *(ptr - 1) = 0;
  380. err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
  381. if (err)
  382. return err;
  383. #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
  384. err = grub_efiemu_autocore ();
  385. if (err)
  386. return err;
  387. #endif
  388. grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);
  389. grub_xnu_lock ();
  390. grub_xnu_is_64bit = 0;
  391. return 0;
  392. }
  393. static grub_err_t
  394. grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
  395. int argc, char *args[])
  396. {
  397. grub_err_t err;
  398. grub_macho_t macho;
  399. grub_uint64_t startcode, endcode;
  400. int i;
  401. char *ptr;
  402. void *loadaddr;
  403. grub_addr_t loadaddr_target;
  404. if (argc < 1)
  405. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
  406. grub_xnu_unload ();
  407. macho = grub_macho_open (args[0], GRUB_FILE_TYPE_XNU_KERNEL, 1);
  408. if (! macho)
  409. return grub_errno;
  410. err = grub_macho_size64 (macho, &startcode, &endcode, GRUB_MACHO_NOBSS,
  411. args[0]);
  412. if (err)
  413. {
  414. grub_macho_close (macho);
  415. grub_xnu_unload ();
  416. return err;
  417. }
  418. startcode &= 0x0fffffff;
  419. endcode &= 0x0fffffff;
  420. grub_dprintf ("xnu", "endcode = %lx, startcode = %lx\n",
  421. (unsigned long) endcode, (unsigned long) startcode);
  422. grub_xnu_relocator = grub_relocator_new ();
  423. if (!grub_xnu_relocator)
  424. return grub_errno;
  425. grub_xnu_heap_target_start = startcode;
  426. err = grub_xnu_heap_malloc (endcode - startcode, &loadaddr,
  427. &loadaddr_target);
  428. if (err)
  429. {
  430. grub_macho_close (macho);
  431. grub_xnu_unload ();
  432. return err;
  433. }
  434. /* Load kernel. */
  435. err = grub_macho_load64 (macho, args[0], (char *) loadaddr - startcode,
  436. GRUB_MACHO_NOBSS, &grub_xnu_darwin_version);
  437. if (err)
  438. {
  439. grub_macho_close (macho);
  440. grub_xnu_unload ();
  441. return err;
  442. }
  443. grub_xnu_entry_point = grub_macho_get_entry_point64 (macho, args[0])
  444. & 0x0fffffff;
  445. if (! grub_xnu_entry_point)
  446. {
  447. grub_macho_close (macho);
  448. grub_xnu_unload ();
  449. return grub_error (GRUB_ERR_BAD_OS, "couldn't find entry point");
  450. }
  451. grub_macho_close (macho);
  452. err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
  453. if (err)
  454. {
  455. grub_xnu_unload ();
  456. return err;
  457. }
  458. /* Copy parameters to kernel command line. */
  459. ptr = grub_xnu_cmdline;
  460. for (i = 1; i < argc; i++)
  461. {
  462. if (ptr + grub_strlen (args[i]) + 1
  463. >= grub_xnu_cmdline + sizeof (grub_xnu_cmdline))
  464. break;
  465. grub_memcpy (ptr, args[i], grub_strlen (args[i]));
  466. ptr += grub_strlen (args[i]);
  467. *ptr = ' ';
  468. ptr++;
  469. }
  470. /* Replace last space by '\0'. */
  471. if (ptr != grub_xnu_cmdline)
  472. *(ptr - 1) = 0;
  473. err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
  474. if (err)
  475. return err;
  476. #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
  477. err = grub_efiemu_autocore ();
  478. if (err)
  479. return err;
  480. #endif
  481. grub_loader_set (grub_xnu_boot, grub_xnu_unload, 0);
  482. grub_xnu_lock ();
  483. grub_xnu_is_64bit = 1;
  484. return 0;
  485. }
  486. /* Register a memory in a memory map under name PREFIXSUFFIX
  487. and increment SUFFIX. */
  488. static grub_err_t
  489. grub_xnu_register_memory (const char *prefix, int *suffix,
  490. grub_addr_t addr, grub_size_t size)
  491. {
  492. struct grub_xnu_devtree_key *chosen;
  493. struct grub_xnu_devtree_key *memorymap;
  494. struct grub_xnu_devtree_key *driverkey;
  495. struct grub_xnu_extdesc *extdesc;
  496. if (! grub_xnu_heap_size)
  497. return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
  498. chosen = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
  499. if (! chosen)
  500. return grub_errno;
  501. memorymap = grub_xnu_create_key (&(chosen->first_child), "memory-map");
  502. if (! memorymap)
  503. return grub_errno;
  504. driverkey = (struct grub_xnu_devtree_key *) grub_malloc (sizeof (*driverkey));
  505. if (! driverkey)
  506. return grub_errno;
  507. if (suffix)
  508. driverkey->name = grub_xasprintf ("%s%d", prefix, (*suffix)++);
  509. else
  510. driverkey->name = grub_strdup (prefix);
  511. if (!driverkey->name)
  512. {
  513. grub_free (driverkey);
  514. return grub_errno;
  515. }
  516. driverkey->datasize = sizeof (*extdesc);
  517. driverkey->next = memorymap->first_child;
  518. driverkey->data = extdesc
  519. = (struct grub_xnu_extdesc *) grub_malloc (sizeof (*extdesc));
  520. if (! driverkey->data)
  521. {
  522. grub_free (driverkey->name);
  523. grub_free (driverkey);
  524. return grub_errno;
  525. }
  526. memorymap->first_child = driverkey;
  527. extdesc->addr = addr;
  528. extdesc->size = (grub_uint32_t) size;
  529. return GRUB_ERR_NONE;
  530. }
  531. static inline char *
  532. get_name_ptr (char *name)
  533. {
  534. char *p = name, *p2;
  535. /* Skip Info.plist. */
  536. p2 = grub_strrchr (p, '/');
  537. if (!p2)
  538. return name;
  539. if (p2 == name)
  540. return name + 1;
  541. p = p2 - 1;
  542. p2 = grub_strrchr (p, '/');
  543. if (!p2)
  544. return name;
  545. if (p2 == name)
  546. return name + 1;
  547. if (grub_memcmp (p2, "/Contents/", sizeof ("/Contents/") - 1) != 0)
  548. return p2 + 1;
  549. p = p2 - 1;
  550. p2 = grub_strrchr (p, '/');
  551. if (!p2)
  552. return name;
  553. return p2 + 1;
  554. }
  555. /* Load .kext. */
  556. static grub_err_t
  557. grub_xnu_load_driver (char *infoplistname, grub_file_t binaryfile,
  558. const char *filename)
  559. {
  560. grub_macho_t macho;
  561. grub_err_t err;
  562. grub_file_t infoplist;
  563. struct grub_xnu_extheader *exthead;
  564. int neededspace = sizeof (*exthead);
  565. grub_uint8_t *buf;
  566. void *buf0;
  567. grub_addr_t buf_target;
  568. grub_size_t infoplistsize = 0, machosize = 0;
  569. char *name, *nameend;
  570. int namelen;
  571. name = get_name_ptr (infoplistname);
  572. nameend = grub_strchr (name, '/');
  573. if (nameend)
  574. namelen = nameend - name;
  575. else
  576. namelen = grub_strlen (name);
  577. neededspace += namelen + 1;
  578. if (! grub_xnu_heap_size)
  579. return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
  580. /* Compute the needed space. */
  581. if (binaryfile)
  582. {
  583. macho = grub_macho_file (binaryfile, filename, grub_xnu_is_64bit);
  584. if (!macho)
  585. grub_file_close (binaryfile);
  586. else
  587. {
  588. if (grub_xnu_is_64bit)
  589. machosize = grub_macho_filesize64 (macho);
  590. else
  591. machosize = grub_macho_filesize32 (macho);
  592. }
  593. neededspace += machosize;
  594. }
  595. else
  596. macho = 0;
  597. if (infoplistname)
  598. infoplist = grub_file_open (infoplistname, GRUB_FILE_TYPE_XNU_INFO_PLIST);
  599. else
  600. infoplist = 0;
  601. grub_errno = GRUB_ERR_NONE;
  602. if (infoplist)
  603. {
  604. infoplistsize = grub_file_size (infoplist);
  605. neededspace += infoplistsize + 1;
  606. }
  607. else
  608. infoplistsize = 0;
  609. /* Allocate the space. */
  610. err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
  611. if (err)
  612. goto fail;
  613. err = grub_xnu_heap_malloc (neededspace, &buf0, &buf_target);
  614. if (err)
  615. goto fail;
  616. buf = buf0;
  617. exthead = (struct grub_xnu_extheader *) buf;
  618. grub_memset (exthead, 0, sizeof (*exthead));
  619. buf += sizeof (*exthead);
  620. /* Load the binary. */
  621. if (macho)
  622. {
  623. exthead->binaryaddr = buf_target + (buf - (grub_uint8_t *) buf0);
  624. exthead->binarysize = machosize;
  625. if (grub_xnu_is_64bit)
  626. err = grub_macho_readfile64 (macho, filename, buf);
  627. else
  628. err = grub_macho_readfile32 (macho, filename, buf);
  629. if (err)
  630. goto fail;
  631. grub_macho_close (macho);
  632. buf += machosize;
  633. }
  634. grub_errno = GRUB_ERR_NONE;
  635. /* Load the plist. */
  636. if (infoplist)
  637. {
  638. exthead->infoplistaddr = buf_target + (buf - (grub_uint8_t *) buf0);
  639. exthead->infoplistsize = infoplistsize + 1;
  640. if (grub_file_read (infoplist, buf, infoplistsize)
  641. != (grub_ssize_t) (infoplistsize))
  642. {
  643. grub_file_close (infoplist);
  644. if (!grub_errno)
  645. grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
  646. infoplistname);
  647. return grub_errno;
  648. }
  649. grub_file_close (infoplist);
  650. buf[infoplistsize] = 0;
  651. buf += infoplistsize + 1;
  652. }
  653. grub_errno = GRUB_ERR_NONE;
  654. exthead->nameaddr = (buf - (grub_uint8_t *) buf0) + buf_target;
  655. exthead->namesize = namelen + 1;
  656. grub_memcpy (buf, name, namelen);
  657. buf[namelen] = 0;
  658. buf += namelen + 1;
  659. /* Announce to kernel */
  660. return grub_xnu_register_memory ("Driver-", &driversnum, buf_target,
  661. neededspace);
  662. fail:
  663. if (macho)
  664. grub_macho_close (macho);
  665. return err;
  666. }
  667. /* Load mkext. */
  668. static grub_err_t
  669. grub_cmd_xnu_mkext (grub_command_t cmd __attribute__ ((unused)),
  670. int argc, char *args[])
  671. {
  672. grub_file_t file;
  673. void *loadto;
  674. grub_addr_t loadto_target;
  675. grub_err_t err;
  676. grub_off_t readoff = 0;
  677. grub_ssize_t readlen = -1;
  678. struct grub_macho_fat_header head;
  679. struct grub_macho_fat_arch *archs;
  680. int narchs, i;
  681. if (argc != 1)
  682. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
  683. if (! grub_xnu_heap_size)
  684. return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
  685. file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_MKEXT);
  686. if (! file)
  687. return grub_errno;
  688. /* Sometimes caches are fat binary. Errgh. */
  689. if (grub_file_read (file, &head, sizeof (head))
  690. != (grub_ssize_t) (sizeof (head)))
  691. {
  692. /* I don't know the internal structure of package but
  693. can hardly imagine a valid package shorter than 20 bytes. */
  694. grub_file_close (file);
  695. if (!grub_errno)
  696. grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]);
  697. return grub_errno;
  698. }
  699. /* Find the corresponding architecture. */
  700. if (grub_be_to_cpu32 (head.magic) == GRUB_MACHO_FAT_MAGIC)
  701. {
  702. narchs = grub_be_to_cpu32 (head.nfat_arch);
  703. archs = grub_malloc (sizeof (struct grub_macho_fat_arch) * narchs);
  704. if (! archs)
  705. {
  706. grub_file_close (file);
  707. return grub_errno;
  708. }
  709. if (grub_file_read (file, archs,
  710. sizeof (struct grub_macho_fat_arch) * narchs)
  711. != (grub_ssize_t) sizeof(struct grub_macho_fat_arch) * narchs)
  712. {
  713. grub_free (archs);
  714. if (!grub_errno)
  715. grub_error (GRUB_ERR_READ_ERROR, N_("premature end of file %s"),
  716. args[0]);
  717. return grub_errno;
  718. }
  719. for (i = 0; i < narchs; i++)
  720. {
  721. if (!grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST32
  722. (grub_be_to_cpu32 (archs[i].cputype)))
  723. {
  724. readoff = grub_be_to_cpu32 (archs[i].offset);
  725. readlen = grub_be_to_cpu32 (archs[i].size);
  726. }
  727. if (grub_xnu_is_64bit && GRUB_MACHO_CPUTYPE_IS_HOST64
  728. (grub_be_to_cpu32 (archs[i].cputype)))
  729. {
  730. readoff = grub_be_to_cpu32 (archs[i].offset);
  731. readlen = grub_be_to_cpu32 (archs[i].size);
  732. }
  733. }
  734. grub_free (archs);
  735. }
  736. else
  737. {
  738. /* It's a flat file. Some sane people still exist. */
  739. readoff = 0;
  740. readlen = grub_file_size (file);
  741. }
  742. if (readlen == -1)
  743. {
  744. grub_file_close (file);
  745. return grub_error (GRUB_ERR_BAD_OS, "no suitable architecture is found");
  746. }
  747. /* Allocate space. */
  748. err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
  749. if (err)
  750. {
  751. grub_file_close (file);
  752. return err;
  753. }
  754. err = grub_xnu_heap_malloc (readlen, &loadto, &loadto_target);
  755. if (err)
  756. {
  757. grub_file_close (file);
  758. return err;
  759. }
  760. /* Read the file. */
  761. grub_file_seek (file, readoff);
  762. if (grub_file_read (file, loadto, readlen) != (grub_ssize_t) (readlen))
  763. {
  764. grub_file_close (file);
  765. if (!grub_errno)
  766. grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]);
  767. return grub_errno;
  768. }
  769. grub_file_close (file);
  770. /* Pass it to kernel. */
  771. return grub_xnu_register_memory ("DriversPackage-", &driverspackagenum,
  772. loadto_target, readlen);
  773. }
  774. static grub_err_t
  775. grub_cmd_xnu_ramdisk (grub_command_t cmd __attribute__ ((unused)),
  776. int argc, char *args[])
  777. {
  778. grub_file_t file;
  779. void *loadto;
  780. grub_addr_t loadto_target;
  781. grub_err_t err;
  782. grub_size_t size;
  783. if (argc != 1)
  784. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
  785. if (! grub_xnu_heap_size)
  786. return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
  787. file = grub_file_open (args[0], GRUB_FILE_TYPE_XNU_RAMDISK);
  788. if (! file)
  789. return grub_errno;
  790. err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
  791. if (err)
  792. return err;
  793. size = grub_file_size (file);
  794. err = grub_xnu_heap_malloc (size, &loadto, &loadto_target);
  795. if (err)
  796. return err;
  797. if (grub_file_read (file, loadto, size) != (grub_ssize_t) (size))
  798. {
  799. grub_file_close (file);
  800. if (!grub_errno)
  801. grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), args[0]);
  802. return grub_errno;
  803. }
  804. return grub_xnu_register_memory ("RAMDisk", 0, loadto_target, size);
  805. }
  806. /* Returns true if the kext should be loaded according to plist
  807. and osbundlereq. Also fill BINNAME. */
  808. static int
  809. grub_xnu_check_os_bundle_required (char *plistname,
  810. const char *osbundlereq,
  811. char **binname)
  812. {
  813. grub_file_t file;
  814. char *buf = 0, *tagstart = 0, *ptr1 = 0, *keyptr = 0;
  815. char *stringptr = 0, *ptr2 = 0;
  816. grub_size_t size;
  817. int depth = 0;
  818. int ret;
  819. int osbundlekeyfound = 0, binnamekeyfound = 0;
  820. if (binname)
  821. *binname = 0;
  822. file = grub_file_open (plistname, GRUB_FILE_TYPE_XNU_INFO_PLIST);
  823. if (! file)
  824. return 0;
  825. size = grub_file_size (file);
  826. buf = grub_malloc (size);
  827. if (! buf)
  828. {
  829. grub_file_close (file);
  830. return 0;
  831. }
  832. if (grub_file_read (file, buf, size) != (grub_ssize_t) (size))
  833. {
  834. grub_file_close (file);
  835. if (!grub_errno)
  836. grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), plistname);
  837. return 0;
  838. }
  839. grub_file_close (file);
  840. /* Set the return value for the case when no OSBundleRequired tag is found. */
  841. if (osbundlereq)
  842. ret = grub_strword (osbundlereq, "all") || grub_strword (osbundlereq, "-");
  843. else
  844. ret = 1;
  845. /* Parse plist. It's quite dirty and inextensible but does its job. */
  846. for (ptr1 = buf; ptr1 < buf + size; ptr1++)
  847. switch (*ptr1)
  848. {
  849. case '<':
  850. tagstart = ptr1;
  851. *ptr1 = 0;
  852. if (keyptr && depth == 4
  853. && grub_strcmp (keyptr, "OSBundleRequired") == 0)
  854. osbundlekeyfound = 1;
  855. if (keyptr && depth == 4 &&
  856. grub_strcmp (keyptr, "CFBundleExecutable") == 0)
  857. binnamekeyfound = 1;
  858. if (stringptr && osbundlekeyfound && osbundlereq && depth == 4)
  859. {
  860. for (ptr2 = stringptr; *ptr2; ptr2++)
  861. *ptr2 = grub_tolower (*ptr2);
  862. ret = grub_strword (osbundlereq, stringptr)
  863. || grub_strword (osbundlereq, "all");
  864. }
  865. if (stringptr && binnamekeyfound && binname && depth == 4)
  866. {
  867. if (*binname)
  868. grub_free (*binname);
  869. *binname = grub_strdup (stringptr);
  870. }
  871. *ptr1 = '<';
  872. keyptr = 0;
  873. stringptr = 0;
  874. break;
  875. case '>':
  876. if (! tagstart)
  877. {
  878. grub_free (buf);
  879. grub_error (GRUB_ERR_BAD_OS, "can't parse %s", plistname);
  880. return 0;
  881. }
  882. *ptr1 = 0;
  883. if (tagstart[1] == '?' || ptr1[-1] == '/')
  884. {
  885. osbundlekeyfound = 0;
  886. *ptr1 = '>';
  887. break;
  888. }
  889. if (depth == 3 && grub_strcmp (tagstart + 1, "key") == 0)
  890. keyptr = ptr1 + 1;
  891. if (depth == 3 && grub_strcmp (tagstart + 1, "string") == 0)
  892. stringptr = ptr1 + 1;
  893. else if (grub_strcmp (tagstart + 1, "/key") != 0)
  894. {
  895. osbundlekeyfound = 0;
  896. binnamekeyfound = 0;
  897. }
  898. *ptr1 = '>';
  899. if (tagstart[1] == '/')
  900. depth--;
  901. else
  902. depth++;
  903. break;
  904. }
  905. grub_free (buf);
  906. return ret;
  907. }
  908. /* Context for grub_xnu_scan_dir_for_kexts. */
  909. struct grub_xnu_scan_dir_for_kexts_ctx
  910. {
  911. char *dirname;
  912. const char *osbundlerequired;
  913. int maxrecursion;
  914. };
  915. /* Helper for grub_xnu_scan_dir_for_kexts. */
  916. static int
  917. grub_xnu_scan_dir_for_kexts_load (const char *filename,
  918. const struct grub_dirhook_info *info,
  919. void *data)
  920. {
  921. struct grub_xnu_scan_dir_for_kexts_ctx *ctx = data;
  922. char *newdirname;
  923. if (! info->dir)
  924. return 0;
  925. if (filename[0] == '.')
  926. return 0;
  927. if (grub_strlen (filename) < 5 ||
  928. grub_memcmp (filename + grub_strlen (filename) - 5, ".kext", 5) != 0)
  929. return 0;
  930. newdirname
  931. = grub_malloc (grub_strlen (ctx->dirname) + grub_strlen (filename) + 2);
  932. /* It's a .kext. Try to load it. */
  933. if (newdirname)
  934. {
  935. grub_strcpy (newdirname, ctx->dirname);
  936. newdirname[grub_strlen (newdirname) + 1] = 0;
  937. newdirname[grub_strlen (newdirname)] = '/';
  938. grub_strcpy (newdirname + grub_strlen (newdirname), filename);
  939. grub_xnu_load_kext_from_dir (newdirname, ctx->osbundlerequired,
  940. ctx->maxrecursion);
  941. if (grub_errno == GRUB_ERR_BAD_OS)
  942. grub_errno = GRUB_ERR_NONE;
  943. grub_free (newdirname);
  944. }
  945. return 0;
  946. }
  947. /* Load all loadable kexts placed under DIRNAME and matching OSBUNDLEREQUIRED */
  948. grub_err_t
  949. grub_xnu_scan_dir_for_kexts (char *dirname, const char *osbundlerequired,
  950. int maxrecursion)
  951. {
  952. struct grub_xnu_scan_dir_for_kexts_ctx ctx = {
  953. .dirname = dirname,
  954. .osbundlerequired = osbundlerequired,
  955. .maxrecursion = maxrecursion
  956. };
  957. grub_device_t dev;
  958. char *device_name;
  959. grub_fs_t fs;
  960. const char *path;
  961. if (! grub_xnu_heap_size)
  962. return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
  963. device_name = grub_file_get_device_name (dirname);
  964. dev = grub_device_open (device_name);
  965. if (dev)
  966. {
  967. fs = grub_fs_probe (dev);
  968. path = grub_strchr (dirname, ')');
  969. if (! path)
  970. path = dirname;
  971. else
  972. path++;
  973. if (fs)
  974. (fs->fs_dir) (dev, path, grub_xnu_scan_dir_for_kexts_load, &ctx);
  975. grub_device_close (dev);
  976. }
  977. grub_free (device_name);
  978. return GRUB_ERR_NONE;
  979. }
  980. /* Context for grub_xnu_load_kext_from_dir. */
  981. struct grub_xnu_load_kext_from_dir_ctx
  982. {
  983. char *dirname;
  984. const char *osbundlerequired;
  985. int maxrecursion;
  986. char *plistname;
  987. char *newdirname;
  988. int usemacos;
  989. };
  990. /* Helper for grub_xnu_load_kext_from_dir. */
  991. static int
  992. grub_xnu_load_kext_from_dir_load (const char *filename,
  993. const struct grub_dirhook_info *info,
  994. void *data)
  995. {
  996. struct grub_xnu_load_kext_from_dir_ctx *ctx = data;
  997. if (grub_strlen (filename) > 15)
  998. return 0;
  999. grub_strcpy (ctx->newdirname + grub_strlen (ctx->dirname) + 1, filename);
  1000. /* If the kext contains directory "Contents" all real stuff is in
  1001. this directory. */
  1002. if (info->dir && grub_strcasecmp (filename, "Contents") == 0)
  1003. grub_xnu_load_kext_from_dir (ctx->newdirname, ctx->osbundlerequired,
  1004. ctx->maxrecursion - 1);
  1005. /* Directory "Plugins" contains nested kexts. */
  1006. if (info->dir && grub_strcasecmp (filename, "Plugins") == 0)
  1007. grub_xnu_scan_dir_for_kexts (ctx->newdirname, ctx->osbundlerequired,
  1008. ctx->maxrecursion - 1);
  1009. /* Directory "MacOS" contains executable, otherwise executable is
  1010. on the top. */
  1011. if (info->dir && grub_strcasecmp (filename, "MacOS") == 0)
  1012. ctx->usemacos = 1;
  1013. /* Info.plist is the file which governs our future actions. */
  1014. if (! info->dir && grub_strcasecmp (filename, "Info.plist") == 0
  1015. && ! ctx->plistname)
  1016. ctx->plistname = grub_strdup (ctx->newdirname);
  1017. return 0;
  1018. }
  1019. /* Load extension DIRNAME. (extensions are directories in xnu) */
  1020. grub_err_t
  1021. grub_xnu_load_kext_from_dir (char *dirname, const char *osbundlerequired,
  1022. int maxrecursion)
  1023. {
  1024. struct grub_xnu_load_kext_from_dir_ctx ctx = {
  1025. .dirname = dirname,
  1026. .osbundlerequired = osbundlerequired,
  1027. .maxrecursion = maxrecursion,
  1028. .plistname = 0,
  1029. .usemacos = 0
  1030. };
  1031. grub_device_t dev;
  1032. char *newpath;
  1033. char *device_name;
  1034. grub_fs_t fs;
  1035. const char *path;
  1036. char *binsuffix;
  1037. grub_file_t binfile;
  1038. ctx.newdirname = grub_malloc (grub_strlen (dirname) + 20);
  1039. if (! ctx.newdirname)
  1040. return grub_errno;
  1041. grub_strcpy (ctx.newdirname, dirname);
  1042. ctx.newdirname[grub_strlen (dirname)] = '/';
  1043. ctx.newdirname[grub_strlen (dirname) + 1] = 0;
  1044. device_name = grub_file_get_device_name (dirname);
  1045. dev = grub_device_open (device_name);
  1046. if (dev)
  1047. {
  1048. fs = grub_fs_probe (dev);
  1049. path = grub_strchr (dirname, ')');
  1050. if (! path)
  1051. path = dirname;
  1052. else
  1053. path++;
  1054. newpath = grub_strchr (ctx.newdirname, ')');
  1055. if (! newpath)
  1056. newpath = ctx.newdirname;
  1057. else
  1058. newpath++;
  1059. /* Look at the directory. */
  1060. if (fs)
  1061. (fs->fs_dir) (dev, path, grub_xnu_load_kext_from_dir_load, &ctx);
  1062. if (ctx.plistname && grub_xnu_check_os_bundle_required
  1063. (ctx.plistname, osbundlerequired, &binsuffix))
  1064. {
  1065. if (binsuffix)
  1066. {
  1067. /* Open the binary. */
  1068. char *binname = grub_malloc (grub_strlen (dirname)
  1069. + grub_strlen (binsuffix)
  1070. + sizeof ("/MacOS/"));
  1071. grub_strcpy (binname, dirname);
  1072. if (ctx.usemacos)
  1073. grub_strcpy (binname + grub_strlen (binname), "/MacOS/");
  1074. else
  1075. grub_strcpy (binname + grub_strlen (binname), "/");
  1076. grub_strcpy (binname + grub_strlen (binname), binsuffix);
  1077. grub_dprintf ("xnu", "%s:%s\n", ctx.plistname, binname);
  1078. binfile = grub_file_open (binname, GRUB_FILE_TYPE_XNU_KEXT);
  1079. if (! binfile)
  1080. grub_errno = GRUB_ERR_NONE;
  1081. /* Load the extension. */
  1082. grub_xnu_load_driver (ctx.plistname, binfile,
  1083. binname);
  1084. grub_free (binname);
  1085. grub_free (binsuffix);
  1086. }
  1087. else
  1088. {
  1089. grub_dprintf ("xnu", "%s:0\n", ctx.plistname);
  1090. grub_xnu_load_driver (ctx.plistname, 0, 0);
  1091. }
  1092. }
  1093. grub_free (ctx.plistname);
  1094. grub_device_close (dev);
  1095. }
  1096. grub_free (device_name);
  1097. return GRUB_ERR_NONE;
  1098. }
  1099. static int locked=0;
  1100. static grub_dl_t my_mod;
  1101. /* Load the kext. */
  1102. static grub_err_t
  1103. grub_cmd_xnu_kext (grub_command_t cmd __attribute__ ((unused)),
  1104. int argc, char *args[])
  1105. {
  1106. grub_file_t binfile = 0;
  1107. if (! grub_xnu_heap_size)
  1108. return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
  1109. if (argc == 2)
  1110. {
  1111. /* User explicitly specified plist and binary. */
  1112. if (grub_strcmp (args[1], "-") != 0)
  1113. {
  1114. binfile = grub_file_open (args[1], GRUB_FILE_TYPE_XNU_KEXT);
  1115. if (! binfile)
  1116. return grub_errno;
  1117. }
  1118. return grub_xnu_load_driver (grub_strcmp (args[0], "-") ? args[0] : 0,
  1119. binfile, args[1]);
  1120. }
  1121. /* load kext normally. */
  1122. if (argc == 1)
  1123. return grub_xnu_load_kext_from_dir (args[0], 0, 10);
  1124. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
  1125. }
  1126. /* Load a directory containing kexts. */
  1127. static grub_err_t
  1128. grub_cmd_xnu_kextdir (grub_command_t cmd __attribute__ ((unused)),
  1129. int argc, char *args[])
  1130. {
  1131. if (argc != 1 && argc != 2)
  1132. return grub_error (GRUB_ERR_BAD_ARGUMENT, "directory name required");
  1133. if (! grub_xnu_heap_size)
  1134. return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
  1135. if (argc == 1)
  1136. return grub_xnu_scan_dir_for_kexts (args[0],
  1137. "console,root,local-root,network-root",
  1138. 10);
  1139. else
  1140. {
  1141. char *osbundlerequired = grub_strdup (args[1]), *ptr;
  1142. grub_err_t err;
  1143. if (! osbundlerequired)
  1144. return grub_errno;
  1145. for (ptr = osbundlerequired; *ptr; ptr++)
  1146. *ptr = grub_tolower (*ptr);
  1147. err = grub_xnu_scan_dir_for_kexts (args[0], osbundlerequired, 10);
  1148. grub_free (osbundlerequired);
  1149. return err;
  1150. }
  1151. }
  1152. static inline int
  1153. hextoval (char c)
  1154. {
  1155. if (c >= '0' && c <= '9')
  1156. return c - '0';
  1157. if (c >= 'a' && c <= 'z')
  1158. return c - 'a' + 10;
  1159. if (c >= 'A' && c <= 'Z')
  1160. return c - 'A' + 10;
  1161. return 0;
  1162. }
  1163. static inline void
  1164. unescape (char *name, char *curdot, char *nextdot, int *len)
  1165. {
  1166. char *ptr, *dptr;
  1167. dptr = name;
  1168. for (ptr = curdot; ptr < nextdot;)
  1169. if (ptr + 2 < nextdot && *ptr == '%')
  1170. {
  1171. *dptr = (hextoval (ptr[1]) << 4) | (hextoval (ptr[2]));
  1172. ptr += 3;
  1173. dptr++;
  1174. }
  1175. else
  1176. {
  1177. *dptr = *ptr;
  1178. ptr++;
  1179. dptr++;
  1180. }
  1181. *len = dptr - name;
  1182. }
  1183. grub_err_t
  1184. grub_xnu_fill_devicetree (void)
  1185. {
  1186. struct grub_env_var *var;
  1187. FOR_SORTED_ENV (var)
  1188. {
  1189. char *nextdot = 0, *curdot;
  1190. struct grub_xnu_devtree_key **curkey = &grub_xnu_devtree_root;
  1191. struct grub_xnu_devtree_key *curvalue;
  1192. char *name = 0, *data;
  1193. int len;
  1194. if (grub_memcmp (var->name, "XNU.DeviceTree.",
  1195. sizeof ("XNU.DeviceTree.") - 1) != 0)
  1196. continue;
  1197. curdot = var->name + sizeof ("XNU.DeviceTree.") - 1;
  1198. nextdot = grub_strchr (curdot, '.');
  1199. if (nextdot)
  1200. nextdot++;
  1201. while (nextdot)
  1202. {
  1203. name = grub_realloc (name, nextdot - curdot + 1);
  1204. if (!name)
  1205. return grub_errno;
  1206. unescape (name, curdot, nextdot, &len);
  1207. name[len - 1] = 0;
  1208. curkey = &(grub_xnu_create_key (curkey, name)->first_child);
  1209. curdot = nextdot;
  1210. nextdot = grub_strchr (nextdot, '.');
  1211. if (nextdot)
  1212. nextdot++;
  1213. }
  1214. nextdot = curdot + grub_strlen (curdot) + 1;
  1215. name = grub_realloc (name, nextdot - curdot + 1);
  1216. if (!name)
  1217. return grub_errno;
  1218. unescape (name, curdot, nextdot, &len);
  1219. name[len] = 0;
  1220. curvalue = grub_xnu_create_value (curkey, name);
  1221. if (!curvalue)
  1222. return grub_errno;
  1223. grub_free (name);
  1224. data = grub_malloc (grub_strlen (var->value) + 1);
  1225. if (!data)
  1226. return grub_errno;
  1227. unescape (data, var->value, var->value + grub_strlen (var->value),
  1228. &len);
  1229. curvalue->datasize = len;
  1230. curvalue->data = data;
  1231. }
  1232. return grub_errno;
  1233. }
  1234. struct grub_video_bitmap *grub_xnu_bitmap = 0;
  1235. grub_xnu_bitmap_mode_t grub_xnu_bitmap_mode;
  1236. /* Option array indices. */
  1237. #define XNU_SPLASH_CMD_ARGINDEX_MODE 0
  1238. static const struct grub_arg_option xnu_splash_cmd_options[] =
  1239. {
  1240. {"mode", 'm', 0, N_("Background image mode."), N_("stretch|normal"),
  1241. ARG_TYPE_STRING},
  1242. {0, 0, 0, 0, 0, 0}
  1243. };
  1244. static grub_err_t
  1245. grub_cmd_xnu_splash (grub_extcmd_context_t ctxt,
  1246. int argc, char *args[])
  1247. {
  1248. grub_err_t err;
  1249. if (argc != 1)
  1250. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
  1251. if (! grub_xnu_heap_size)
  1252. return grub_error (GRUB_ERR_BAD_OS, N_("you need to load the kernel first"));
  1253. if (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].set &&
  1254. grub_strcmp (ctxt->state[XNU_SPLASH_CMD_ARGINDEX_MODE].arg,
  1255. "stretch") == 0)
  1256. grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_STRETCH;
  1257. else
  1258. grub_xnu_bitmap_mode = GRUB_XNU_BITMAP_CENTER;
  1259. err = grub_video_bitmap_load (&grub_xnu_bitmap, args[0]);
  1260. if (err)
  1261. grub_xnu_bitmap = 0;
  1262. return err;
  1263. }
  1264. #ifndef GRUB_MACHINE_EMU
  1265. static grub_err_t
  1266. grub_cmd_xnu_resume (grub_command_t cmd __attribute__ ((unused)),
  1267. int argc, char *args[])
  1268. {
  1269. if (argc != 1)
  1270. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
  1271. return grub_xnu_resume (args[0]);
  1272. }
  1273. #endif
  1274. void
  1275. grub_xnu_lock (void)
  1276. {
  1277. if (!locked)
  1278. grub_dl_ref (my_mod);
  1279. locked = 1;
  1280. }
  1281. void
  1282. grub_xnu_unlock (void)
  1283. {
  1284. if (locked)
  1285. grub_dl_unref (my_mod);
  1286. locked = 0;
  1287. }
  1288. static grub_command_t cmd_kernel64, cmd_kernel, cmd_mkext, cmd_kext;
  1289. static grub_command_t cmd_kextdir, cmd_ramdisk, cmd_resume;
  1290. static grub_extcmd_t cmd_splash;
  1291. GRUB_MOD_INIT(xnu)
  1292. {
  1293. cmd_kernel = grub_register_command ("xnu_kernel", grub_cmd_xnu_kernel, 0,
  1294. N_("Load XNU image."));
  1295. cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64,
  1296. 0, N_("Load 64-bit XNU image."));
  1297. cmd_mkext = grub_register_command ("xnu_mkext", grub_cmd_xnu_mkext, 0,
  1298. N_("Load XNU extension package."));
  1299. cmd_kext = grub_register_command ("xnu_kext", grub_cmd_xnu_kext, 0,
  1300. N_("Load XNU extension."));
  1301. cmd_kextdir = grub_register_command ("xnu_kextdir", grub_cmd_xnu_kextdir,
  1302. /* TRANSLATORS: OSBundleRequired is a
  1303. variable name in xnu extensions
  1304. manifests. It behaves mostly like
  1305. GNU/Linux runlevels.
  1306. */
  1307. N_("DIRECTORY [OSBundleRequired]"),
  1308. /* TRANSLATORS: There are many extensions
  1309. in extension directory. */
  1310. N_("Load XNU extension directory."));
  1311. cmd_ramdisk = grub_register_command ("xnu_ramdisk", grub_cmd_xnu_ramdisk, 0,
  1312. /* TRANSLATORS: ramdisk here isn't identifier. It can be translated. */
  1313. N_("Load XNU ramdisk. "
  1314. "It will be available in OS as md0."));
  1315. cmd_splash = grub_register_extcmd ("xnu_splash",
  1316. grub_cmd_xnu_splash, 0, 0,
  1317. N_("Load a splash image for XNU."),
  1318. xnu_splash_cmd_options);
  1319. #ifndef GRUB_MACHINE_EMU
  1320. cmd_resume = grub_register_command ("xnu_resume", grub_cmd_xnu_resume,
  1321. 0, N_("Load an image of hibernated"
  1322. " XNU."));
  1323. #endif
  1324. grub_cpu_xnu_init ();
  1325. my_mod = mod;
  1326. }
  1327. GRUB_MOD_FINI(xnu)
  1328. {
  1329. #ifndef GRUB_MACHINE_EMU
  1330. grub_unregister_command (cmd_resume);
  1331. #endif
  1332. grub_unregister_command (cmd_mkext);
  1333. grub_unregister_command (cmd_kext);
  1334. grub_unregister_command (cmd_kextdir);
  1335. grub_unregister_command (cmd_ramdisk);
  1336. grub_unregister_command (cmd_kernel);
  1337. grub_unregister_extcmd (cmd_splash);
  1338. grub_unregister_command (cmd_kernel64);
  1339. grub_cpu_xnu_fini ();
  1340. }