xnu.c 38 KB

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