xnu.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2009 Free Software Foundation, Inc.
  4. *
  5. * GRUB is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * GRUB is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/env.h>
  19. #include <grub/file.h>
  20. #include <grub/disk.h>
  21. #include <grub/xnu.h>
  22. #include <grub/cpu/xnu.h>
  23. #include <grub/mm.h>
  24. #include <grub/loader.h>
  25. #include <grub/autoefi.h>
  26. #include <grub/i386/tsc.h>
  27. #include <grub/i386/cpuid.h>
  28. #include <grub/efi/api.h>
  29. #include <grub/i386/pit.h>
  30. #include <grub/misc.h>
  31. #include <grub/charset.h>
  32. #include <grub/term.h>
  33. #include <grub/command.h>
  34. #include <grub/i18n.h>
  35. #include <grub/bitmap_scale.h>
  36. #include <grub/cpu/io.h>
  37. #include <grub/random.h>
  38. #define min(a,b) (((a) < (b)) ? (a) : (b))
  39. #define max(a,b) (((a) > (b)) ? (a) : (b))
  40. #define DEFAULT_VIDEO_MODE "auto"
  41. char grub_xnu_cmdline[1024];
  42. grub_uint32_t grub_xnu_entry_point, grub_xnu_arg1, grub_xnu_stack;
  43. /* Aliases set for some tables. */
  44. struct tbl_alias
  45. {
  46. grub_efi_guid_t guid;
  47. const char *name;
  48. };
  49. static struct tbl_alias table_aliases[] =
  50. {
  51. {GRUB_EFI_ACPI_20_TABLE_GUID, "ACPI_20"},
  52. {GRUB_EFI_ACPI_TABLE_GUID, "ACPI"},
  53. };
  54. struct grub_xnu_devprop_device_descriptor
  55. {
  56. struct grub_xnu_devprop_device_descriptor *next;
  57. struct grub_xnu_devprop_device_descriptor **prev;
  58. struct property_descriptor *properties;
  59. struct grub_efi_device_path *path;
  60. int pathlen;
  61. };
  62. static int
  63. utf16_strlen (grub_uint16_t *in)
  64. {
  65. int i;
  66. for (i = 0; in[i]; i++);
  67. return i;
  68. }
  69. /* Read frequency from a string in MHz and return it in Hz. */
  70. static grub_uint64_t
  71. readfrequency (const char *str)
  72. {
  73. grub_uint64_t num = 0;
  74. int mul = 1000000;
  75. int found = 0;
  76. while (*str)
  77. {
  78. unsigned long digit;
  79. digit = grub_tolower (*str) - '0';
  80. if (digit > 9)
  81. break;
  82. found = 1;
  83. num = num * 10 + digit;
  84. str++;
  85. }
  86. num *= 1000000;
  87. if (*str == '.')
  88. {
  89. str++;
  90. while (*str)
  91. {
  92. unsigned long digit;
  93. digit = grub_tolower (*str) - '0';
  94. if (digit > 9)
  95. break;
  96. found = 1;
  97. mul /= 10;
  98. num = num + mul * digit;
  99. str++;
  100. }
  101. }
  102. if (! found)
  103. return 0;
  104. return num;
  105. }
  106. /* Thanks to Kabyl for precious information about Intel architecture. */
  107. static grub_uint64_t
  108. guessfsb (void)
  109. {
  110. const grub_uint64_t sane_value = 100000000;
  111. grub_uint32_t manufacturer[3], max_cpuid, capabilities, msrlow;
  112. grub_uint32_t a, b, d, divisor;
  113. if (! grub_cpu_is_cpuid_supported ())
  114. return sane_value;
  115. grub_cpuid (0, max_cpuid, manufacturer[0], manufacturer[2], manufacturer[1]);
  116. /* Only Intel for now is done. */
  117. if (grub_memcmp (manufacturer, "GenuineIntel", 12) != 0)
  118. return sane_value;
  119. /* Check Speedstep. */
  120. if (max_cpuid < 1)
  121. return sane_value;
  122. grub_cpuid (1, a, b, capabilities, d);
  123. if (! (capabilities & (1 << 7)))
  124. return sane_value;
  125. /* Read the multiplier. */
  126. asm volatile ("movl $0x198, %%ecx\n"
  127. "rdmsr"
  128. : "=d" (msrlow)
  129. :
  130. : "%ecx", "%eax");
  131. grub_uint64_t v;
  132. grub_uint32_t r;
  133. /* (2000ULL << 32) / grub_tsc_rate */
  134. /* Assumption: TSC frequency is over 2 MHz. */
  135. v = 0xffffffff / grub_tsc_rate;
  136. v *= 2000;
  137. /* v is at most 2000 off from (2000ULL << 32) / grub_tsc_rate.
  138. Since grub_tsc_rate < 2^32/2^11=2^21, so no overflow.
  139. */
  140. r = (2000ULL << 32) - v * grub_tsc_rate;
  141. v += r / grub_tsc_rate;
  142. divisor = ((msrlow >> 7) & 0x3e) | ((msrlow >> 14) & 1);
  143. if (divisor == 0)
  144. return sane_value;
  145. return grub_divmod64 (v, divisor, 0);
  146. }
  147. struct property_descriptor
  148. {
  149. struct property_descriptor *next;
  150. struct property_descriptor **prev;
  151. grub_uint8_t *name;
  152. grub_uint16_t *name16;
  153. int name16len;
  154. int length;
  155. void *data;
  156. };
  157. static struct grub_xnu_devprop_device_descriptor *devices = 0;
  158. grub_err_t
  159. grub_xnu_devprop_remove_property (struct grub_xnu_devprop_device_descriptor *dev,
  160. char *name)
  161. {
  162. struct property_descriptor *prop;
  163. prop = grub_named_list_find (GRUB_AS_NAMED_LIST (dev->properties), name);
  164. if (!prop)
  165. return GRUB_ERR_NONE;
  166. grub_free (prop->name);
  167. grub_free (prop->name16);
  168. grub_free (prop->data);
  169. grub_list_remove (GRUB_AS_LIST (prop));
  170. return GRUB_ERR_NONE;
  171. }
  172. grub_err_t
  173. grub_xnu_devprop_remove_device (struct grub_xnu_devprop_device_descriptor *dev)
  174. {
  175. void *t;
  176. struct property_descriptor *prop;
  177. grub_list_remove (GRUB_AS_LIST (dev));
  178. for (prop = dev->properties; prop; )
  179. {
  180. grub_free (prop->name);
  181. grub_free (prop->name16);
  182. grub_free (prop->data);
  183. t = prop;
  184. prop = prop->next;
  185. grub_free (t);
  186. }
  187. grub_free (dev->path);
  188. grub_free (dev);
  189. return GRUB_ERR_NONE;
  190. }
  191. struct grub_xnu_devprop_device_descriptor *
  192. grub_xnu_devprop_add_device (struct grub_efi_device_path *path, int length)
  193. {
  194. struct grub_xnu_devprop_device_descriptor *ret;
  195. ret = grub_zalloc (sizeof (*ret));
  196. if (!ret)
  197. return 0;
  198. ret->path = grub_malloc (length);
  199. if (!ret->path)
  200. {
  201. grub_free (ret);
  202. return 0;
  203. }
  204. ret->pathlen = length;
  205. grub_memcpy (ret->path, path, length);
  206. grub_list_push (GRUB_AS_LIST_P (&devices), GRUB_AS_LIST (ret));
  207. return ret;
  208. }
  209. static grub_err_t
  210. grub_xnu_devprop_add_property (struct grub_xnu_devprop_device_descriptor *dev,
  211. grub_uint8_t *utf8, grub_uint16_t *utf16,
  212. int utf16len, void *data, int datalen)
  213. {
  214. struct property_descriptor *prop;
  215. prop = grub_malloc (sizeof (*prop));
  216. if (!prop)
  217. return grub_errno;
  218. prop->name = utf8;
  219. prop->name16 = utf16;
  220. prop->name16len = utf16len;
  221. prop->length = datalen;
  222. prop->data = grub_malloc (prop->length);
  223. if (!prop->data)
  224. {
  225. grub_free (prop->name);
  226. grub_free (prop->name16);
  227. grub_free (prop);
  228. return grub_errno;
  229. }
  230. grub_memcpy (prop->data, data, prop->length);
  231. grub_list_push (GRUB_AS_LIST_P (&dev->properties),
  232. GRUB_AS_LIST (prop));
  233. return GRUB_ERR_NONE;
  234. }
  235. grub_err_t
  236. grub_xnu_devprop_add_property_utf8 (struct grub_xnu_devprop_device_descriptor *dev,
  237. char *name, void *data, int datalen)
  238. {
  239. grub_uint8_t *utf8;
  240. grub_uint16_t *utf16;
  241. int len, utf16len;
  242. grub_err_t err;
  243. utf8 = (grub_uint8_t *) grub_strdup (name);
  244. if (!utf8)
  245. return grub_errno;
  246. len = grub_strlen (name);
  247. utf16 = grub_malloc (sizeof (grub_uint16_t) * len);
  248. if (!utf16)
  249. {
  250. grub_free (utf8);
  251. return grub_errno;
  252. }
  253. utf16len = grub_utf8_to_utf16 (utf16, len, utf8, len, NULL);
  254. if (utf16len < 0)
  255. {
  256. grub_free (utf8);
  257. grub_free (utf16);
  258. return grub_errno;
  259. }
  260. err = grub_xnu_devprop_add_property (dev, utf8, utf16,
  261. utf16len, data, datalen);
  262. if (err)
  263. {
  264. grub_free (utf8);
  265. grub_free (utf16);
  266. return err;
  267. }
  268. return GRUB_ERR_NONE;
  269. }
  270. grub_err_t
  271. grub_xnu_devprop_add_property_utf16 (struct grub_xnu_devprop_device_descriptor *dev,
  272. grub_uint16_t *name, int namelen,
  273. void *data, int datalen)
  274. {
  275. grub_uint8_t *utf8;
  276. grub_uint16_t *utf16;
  277. grub_err_t err;
  278. utf16 = grub_malloc (sizeof (grub_uint16_t) * namelen);
  279. if (!utf16)
  280. return grub_errno;
  281. grub_memcpy (utf16, name, sizeof (grub_uint16_t) * namelen);
  282. utf8 = grub_malloc (namelen * 4 + 1);
  283. if (!utf8)
  284. {
  285. grub_free (utf16);
  286. return grub_errno;
  287. }
  288. *grub_utf16_to_utf8 ((grub_uint8_t *) utf8, name, namelen) = '\0';
  289. err = grub_xnu_devprop_add_property (dev, utf8, utf16,
  290. namelen, data, datalen);
  291. if (err)
  292. {
  293. grub_free (utf8);
  294. grub_free (utf16);
  295. return err;
  296. }
  297. return GRUB_ERR_NONE;
  298. }
  299. void
  300. grub_cpu_xnu_unload (void)
  301. {
  302. struct grub_xnu_devprop_device_descriptor *dev1, *dev2;
  303. for (dev1 = devices; dev1; )
  304. {
  305. dev2 = dev1->next;
  306. grub_xnu_devprop_remove_device (dev1);
  307. dev1 = dev2;
  308. }
  309. }
  310. static grub_err_t
  311. grub_cpu_xnu_fill_devprop (void)
  312. {
  313. struct grub_xnu_devtree_key *efikey;
  314. int total_length = sizeof (struct grub_xnu_devprop_header);
  315. struct grub_xnu_devtree_key *devprop;
  316. struct grub_xnu_devprop_device_descriptor *device;
  317. void *ptr;
  318. struct grub_xnu_devprop_header *head;
  319. void *t;
  320. int numdevs = 0;
  321. /* The key "efi". */
  322. efikey = grub_xnu_create_key (&grub_xnu_devtree_root, "efi");
  323. if (! efikey)
  324. return grub_errno;
  325. for (device = devices; device; device = device->next)
  326. {
  327. struct property_descriptor *propdesc;
  328. total_length += sizeof (struct grub_xnu_devprop_device_header);
  329. total_length += device->pathlen;
  330. for (propdesc = device->properties; propdesc; propdesc = propdesc->next)
  331. {
  332. total_length += sizeof (grub_uint32_t);
  333. total_length += sizeof (grub_uint16_t)
  334. * (propdesc->name16len + 1);
  335. total_length += sizeof (grub_uint32_t);
  336. total_length += propdesc->length;
  337. }
  338. numdevs++;
  339. }
  340. devprop = grub_xnu_create_value (&(efikey->first_child), "device-properties");
  341. if (!devprop)
  342. return grub_errno;
  343. devprop->data = grub_malloc (total_length);
  344. devprop->datasize = total_length;
  345. ptr = devprop->data;
  346. head = ptr;
  347. ptr = head + 1;
  348. head->length = total_length;
  349. head->alwaysone = 1;
  350. head->num_devices = numdevs;
  351. for (device = devices; device; )
  352. {
  353. struct grub_xnu_devprop_device_header *devhead;
  354. struct property_descriptor *propdesc;
  355. devhead = ptr;
  356. devhead->num_values = 0;
  357. ptr = devhead + 1;
  358. grub_memcpy (ptr, device->path, device->pathlen);
  359. ptr = (char *) ptr + device->pathlen;
  360. for (propdesc = device->properties; propdesc; )
  361. {
  362. grub_uint32_t *len;
  363. grub_uint16_t *name;
  364. void *data;
  365. len = ptr;
  366. *len = 2 * propdesc->name16len + sizeof (grub_uint16_t)
  367. + sizeof (grub_uint32_t);
  368. ptr = len + 1;
  369. name = ptr;
  370. grub_memcpy (name, propdesc->name16, 2 * propdesc->name16len);
  371. name += propdesc->name16len;
  372. /* NUL terminator. */
  373. *name = 0;
  374. ptr = name + 1;
  375. len = ptr;
  376. *len = propdesc->length + sizeof (grub_uint32_t);
  377. data = len + 1;
  378. ptr = data;
  379. grub_memcpy (ptr, propdesc->data, propdesc->length);
  380. ptr = (char *) ptr + propdesc->length;
  381. grub_free (propdesc->name);
  382. grub_free (propdesc->name16);
  383. grub_free (propdesc->data);
  384. t = propdesc;
  385. propdesc = propdesc->next;
  386. grub_free (t);
  387. devhead->num_values++;
  388. }
  389. devhead->length = (char *) ptr - (char *) devhead;
  390. t = device;
  391. device = device->next;
  392. grub_free (t);
  393. }
  394. devices = 0;
  395. return GRUB_ERR_NONE;
  396. }
  397. static grub_err_t
  398. grub_cmd_devprop_load (grub_command_t cmd __attribute__ ((unused)),
  399. int argc, char *args[])
  400. {
  401. grub_file_t file;
  402. void *buf, *bufstart, *bufend;
  403. struct grub_xnu_devprop_header *head;
  404. grub_size_t size;
  405. unsigned i, j;
  406. if (argc != 1)
  407. return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
  408. file = grub_file_open (args[0]);
  409. if (! file)
  410. return grub_errno;
  411. size = grub_file_size (file);
  412. buf = grub_malloc (size);
  413. if (!buf)
  414. {
  415. grub_file_close (file);
  416. return grub_errno;
  417. }
  418. if (grub_file_read (file, buf, size) != (grub_ssize_t) size)
  419. {
  420. grub_file_close (file);
  421. return grub_errno;
  422. }
  423. grub_file_close (file);
  424. bufstart = buf;
  425. bufend = (char *) buf + size;
  426. head = buf;
  427. buf = head + 1;
  428. for (i = 0; i < grub_le_to_cpu32 (head->num_devices) && buf < bufend; i++)
  429. {
  430. struct grub_efi_device_path *dp, *dpstart;
  431. struct grub_xnu_devprop_device_descriptor *dev;
  432. struct grub_xnu_devprop_device_header *devhead;
  433. devhead = buf;
  434. buf = devhead + 1;
  435. dpstart = buf;
  436. do
  437. {
  438. dp = buf;
  439. buf = (char *) buf + GRUB_EFI_DEVICE_PATH_LENGTH (dp);
  440. }
  441. while (!GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp) && buf < bufend);
  442. dev = grub_xnu_devprop_add_device (dpstart, (char *) buf
  443. - (char *) dpstart);
  444. for (j = 0; j < grub_le_to_cpu32 (devhead->num_values) && buf < bufend;
  445. j++)
  446. {
  447. grub_uint32_t *namelen;
  448. grub_uint32_t *datalen;
  449. grub_uint16_t *utf16;
  450. void *data;
  451. grub_err_t err;
  452. namelen = buf;
  453. buf = namelen + 1;
  454. if (buf >= bufend)
  455. break;
  456. utf16 = buf;
  457. buf = (char *) buf + *namelen - sizeof (grub_uint32_t);
  458. if (buf >= bufend)
  459. break;
  460. datalen = buf;
  461. buf = datalen + 1;
  462. if (buf >= bufend)
  463. break;
  464. data = buf;
  465. buf = (char *) buf + *datalen - sizeof (grub_uint32_t);
  466. if (buf >= bufend)
  467. break;
  468. err = grub_xnu_devprop_add_property_utf16
  469. (dev, utf16, (*namelen - sizeof (grub_uint32_t)
  470. - sizeof (grub_uint16_t)) / sizeof (grub_uint16_t),
  471. data, *datalen - sizeof (grub_uint32_t));
  472. if (err)
  473. {
  474. grub_free (bufstart);
  475. return err;
  476. }
  477. }
  478. }
  479. grub_free (bufstart);
  480. return GRUB_ERR_NONE;
  481. }
  482. /* Fill device tree. */
  483. /* FIXME: some entries may be platform-agnostic. Move them to loader/xnu.c. */
  484. static grub_err_t
  485. grub_cpu_xnu_fill_devicetree (grub_uint64_t *fsbfreq_out)
  486. {
  487. struct grub_xnu_devtree_key *efikey;
  488. struct grub_xnu_devtree_key *chosenkey;
  489. struct grub_xnu_devtree_key *cfgtablekey;
  490. struct grub_xnu_devtree_key *curval;
  491. struct grub_xnu_devtree_key *runtimesrvkey;
  492. struct grub_xnu_devtree_key *platformkey;
  493. unsigned i, j;
  494. grub_err_t err;
  495. chosenkey = grub_xnu_create_key (&grub_xnu_devtree_root, "chosen");
  496. if (! chosenkey)
  497. return grub_errno;
  498. /* Random seed. */
  499. curval = grub_xnu_create_value (&(chosenkey->first_child), "random-seed");
  500. if (! curval)
  501. return grub_errno;
  502. curval->datasize = 64;
  503. curval->data = grub_malloc (curval->datasize);
  504. if (! curval->data)
  505. return grub_errno;
  506. /* Our random is not peer-reviewed but xnu uses this seed only for
  507. ASLR in kernel. */
  508. err = grub_crypto_get_random (curval->data, curval->datasize);
  509. if (err)
  510. return err;
  511. /* The value "model". */
  512. /* FIXME: may this value be sometimes different? */
  513. curval = grub_xnu_create_value (&grub_xnu_devtree_root, "model");
  514. if (! curval)
  515. return grub_errno;
  516. curval->datasize = sizeof ("ACPI");
  517. curval->data = grub_strdup ("ACPI");
  518. curval = grub_xnu_create_value (&grub_xnu_devtree_root, "compatible");
  519. if (! curval)
  520. return grub_errno;
  521. curval->datasize = sizeof ("ACPI");
  522. curval->data = grub_strdup ("ACPI");
  523. /* The key "efi". */
  524. efikey = grub_xnu_create_key (&grub_xnu_devtree_root, "efi");
  525. if (! efikey)
  526. return grub_errno;
  527. /* Information about firmware. */
  528. curval = grub_xnu_create_value (&(efikey->first_child), "firmware-revision");
  529. if (! curval)
  530. return grub_errno;
  531. curval->datasize = (SYSTEM_TABLE_SIZEOF (firmware_revision));
  532. curval->data = grub_malloc (curval->datasize);
  533. if (! curval->data)
  534. return grub_errno;
  535. grub_memcpy (curval->data, (SYSTEM_TABLE_VAR(firmware_revision)),
  536. curval->datasize);
  537. curval = grub_xnu_create_value (&(efikey->first_child), "firmware-vendor");
  538. if (! curval)
  539. return grub_errno;
  540. curval->datasize =
  541. 2 * (utf16_strlen (SYSTEM_TABLE_PTR (firmware_vendor)) + 1);
  542. curval->data = grub_malloc (curval->datasize);
  543. if (! curval->data)
  544. return grub_errno;
  545. grub_memcpy (curval->data, SYSTEM_TABLE_PTR (firmware_vendor),
  546. curval->datasize);
  547. curval = grub_xnu_create_value (&(efikey->first_child), "firmware-abi");
  548. if (! curval)
  549. return grub_errno;
  550. curval->datasize = sizeof ("EFI32");
  551. curval->data = grub_malloc (curval->datasize);
  552. if (! curval->data)
  553. return grub_errno;
  554. if (SIZEOF_OF_UINTN == 4)
  555. grub_memcpy (curval->data, "EFI32", curval->datasize);
  556. else
  557. grub_memcpy (curval->data, "EFI64", curval->datasize);
  558. /* The key "platform". */
  559. platformkey = grub_xnu_create_key (&(efikey->first_child),
  560. "platform");
  561. if (! platformkey)
  562. return grub_errno;
  563. /* Pass FSB frequency to the kernel. */
  564. curval = grub_xnu_create_value (&(platformkey->first_child), "FSBFrequency");
  565. if (! curval)
  566. return grub_errno;
  567. curval->datasize = sizeof (grub_uint64_t);
  568. curval->data = grub_malloc (curval->datasize);
  569. if (!curval->data)
  570. return grub_errno;
  571. /* First see if user supplies the value. */
  572. const char *fsbvar = grub_env_get ("fsb");
  573. grub_uint64_t fsbfreq = 0;
  574. if (fsbvar)
  575. fsbfreq = readfrequency (fsbvar);
  576. /* Try autodetect. */
  577. if (! fsbfreq)
  578. fsbfreq = guessfsb ();
  579. *((grub_uint64_t *) curval->data) = fsbfreq;
  580. *fsbfreq_out = fsbfreq;
  581. grub_dprintf ("xnu", "fsb autodetected as %llu\n",
  582. (unsigned long long) *((grub_uint64_t *) curval->data));
  583. cfgtablekey = grub_xnu_create_key (&(efikey->first_child),
  584. "configuration-table");
  585. if (!cfgtablekey)
  586. return grub_errno;
  587. /* Fill "configuration-table" key. */
  588. for (i = 0; i < SYSTEM_TABLE (num_table_entries); i++)
  589. {
  590. void *ptr;
  591. struct grub_xnu_devtree_key *curkey;
  592. grub_efi_packed_guid_t guid;
  593. char guidbuf[64];
  594. /* Retrieve current key. */
  595. #ifdef GRUB_MACHINE_EFI
  596. {
  597. ptr = (void *)
  598. grub_efi_system_table->configuration_table[i].vendor_table;
  599. guid = grub_efi_system_table->configuration_table[i].vendor_guid;
  600. }
  601. #else
  602. if (SIZEOF_OF_UINTN == 4)
  603. {
  604. ptr = (void *) (grub_addr_t) ((grub_efiemu_configuration_table32_t *)
  605. SYSTEM_TABLE_PTR (configuration_table))[i]
  606. .vendor_table;
  607. guid =
  608. ((grub_efiemu_configuration_table32_t *)
  609. SYSTEM_TABLE_PTR (configuration_table))[i].vendor_guid;
  610. }
  611. else
  612. {
  613. ptr = (void *) (grub_addr_t) ((grub_efiemu_configuration_table64_t *)
  614. SYSTEM_TABLE_PTR (configuration_table))[i]
  615. .vendor_table;
  616. guid =
  617. ((grub_efiemu_configuration_table64_t *)
  618. SYSTEM_TABLE_PTR (configuration_table))[i].vendor_guid;
  619. }
  620. #endif
  621. /* The name of key for new table. */
  622. grub_snprintf (guidbuf, sizeof (guidbuf), "%08x-%04x-%04x-%02x%02x-",
  623. guid.data1, guid.data2, guid.data3, guid.data4[0],
  624. guid.data4[1]);
  625. for (j = 2; j < 8; j++)
  626. grub_snprintf (guidbuf + grub_strlen (guidbuf),
  627. sizeof (guidbuf) - grub_strlen (guidbuf),
  628. "%02x", guid.data4[j]);
  629. /* For some reason GUID has to be in uppercase. */
  630. for (j = 0; guidbuf[j] ; j++)
  631. if (guidbuf[j] >= 'a' && guidbuf[j] <= 'f')
  632. guidbuf[j] += 'A' - 'a';
  633. curkey = grub_xnu_create_key (&(cfgtablekey->first_child), guidbuf);
  634. if (! curkey)
  635. return grub_errno;
  636. curval = grub_xnu_create_value (&(curkey->first_child), "guid");
  637. if (! curval)
  638. return grub_errno;
  639. curval->datasize = sizeof (guid);
  640. curval->data = grub_malloc (curval->datasize);
  641. if (! curval->data)
  642. return grub_errno;
  643. grub_memcpy (curval->data, &guid, curval->datasize);
  644. /* The value "table". */
  645. curval = grub_xnu_create_value (&(curkey->first_child), "table");
  646. if (! curval)
  647. return grub_errno;
  648. curval->datasize = SIZEOF_OF_UINTN;
  649. curval->data = grub_malloc (curval->datasize);
  650. if (! curval->data)
  651. return grub_errno;
  652. if (SIZEOF_OF_UINTN == 4)
  653. *((grub_uint32_t *) curval->data) = (grub_addr_t) ptr;
  654. else
  655. *((grub_uint64_t *) curval->data) = (grub_addr_t) ptr;
  656. /* Create alias. */
  657. for (j = 0; j < ARRAY_SIZE(table_aliases); j++)
  658. if (grub_memcmp (&table_aliases[j].guid, &guid, sizeof (guid)) == 0)
  659. break;
  660. if (j != ARRAY_SIZE(table_aliases))
  661. {
  662. curval = grub_xnu_create_value (&(curkey->first_child), "alias");
  663. if (!curval)
  664. return grub_errno;
  665. curval->datasize = grub_strlen (table_aliases[j].name) + 1;
  666. curval->data = grub_malloc (curval->datasize);
  667. if (!curval->data)
  668. return grub_errno;
  669. grub_memcpy (curval->data, table_aliases[j].name, curval->datasize);
  670. }
  671. }
  672. /* Create and fill "runtime-services" key. */
  673. runtimesrvkey = grub_xnu_create_key (&(efikey->first_child),
  674. "runtime-services");
  675. if (! runtimesrvkey)
  676. return grub_errno;
  677. curval = grub_xnu_create_value (&(runtimesrvkey->first_child), "table");
  678. if (! curval)
  679. return grub_errno;
  680. curval->datasize = SIZEOF_OF_UINTN;
  681. curval->data = grub_malloc (curval->datasize);
  682. if (! curval->data)
  683. return grub_errno;
  684. if (SIZEOF_OF_UINTN == 4)
  685. *((grub_uint32_t *) curval->data)
  686. = (grub_addr_t) SYSTEM_TABLE_PTR (runtime_services);
  687. else
  688. *((grub_uint64_t *) curval->data)
  689. = (grub_addr_t) SYSTEM_TABLE_PTR (runtime_services);
  690. return GRUB_ERR_NONE;
  691. }
  692. grub_err_t
  693. grub_xnu_boot_resume (void)
  694. {
  695. struct grub_relocator32_state state;
  696. state.esp = grub_xnu_stack;
  697. state.ebp = grub_xnu_stack;
  698. state.eip = grub_xnu_entry_point;
  699. state.eax = grub_xnu_arg1;
  700. return grub_relocator32_boot (grub_xnu_relocator, state, 0);
  701. }
  702. /* Setup video for xnu. */
  703. static grub_err_t
  704. grub_xnu_set_video (struct grub_xnu_boot_params_common *params)
  705. {
  706. struct grub_video_mode_info mode_info;
  707. char *tmp;
  708. const char *modevar;
  709. void *framebuffer;
  710. grub_err_t err;
  711. struct grub_video_bitmap *bitmap = NULL;
  712. modevar = grub_env_get ("gfxpayload");
  713. /* Consider only graphical 32-bit deep modes. */
  714. if (! modevar || *modevar == 0)
  715. err = grub_video_set_mode (DEFAULT_VIDEO_MODE,
  716. GRUB_VIDEO_MODE_TYPE_PURE_TEXT
  717. | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK,
  718. 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS);
  719. else
  720. {
  721. tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
  722. if (! tmp)
  723. return grub_errno;
  724. err = grub_video_set_mode (tmp,
  725. GRUB_VIDEO_MODE_TYPE_PURE_TEXT
  726. | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK,
  727. 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS);
  728. grub_free (tmp);
  729. }
  730. if (err)
  731. return err;
  732. err = grub_video_get_info (&mode_info);
  733. if (err)
  734. return err;
  735. if (grub_xnu_bitmap)
  736. {
  737. if (grub_xnu_bitmap_mode == GRUB_XNU_BITMAP_STRETCH)
  738. err = grub_video_bitmap_create_scaled (&bitmap,
  739. mode_info.width,
  740. mode_info.height,
  741. grub_xnu_bitmap,
  742. GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
  743. else
  744. bitmap = grub_xnu_bitmap;
  745. }
  746. if (bitmap)
  747. {
  748. if (grub_xnu_bitmap_mode == GRUB_XNU_BITMAP_STRETCH)
  749. err = grub_video_bitmap_create_scaled (&bitmap,
  750. mode_info.width,
  751. mode_info.height,
  752. grub_xnu_bitmap,
  753. GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
  754. else
  755. bitmap = grub_xnu_bitmap;
  756. }
  757. if (bitmap)
  758. {
  759. int x, y;
  760. x = mode_info.width - bitmap->mode_info.width;
  761. x /= 2;
  762. y = mode_info.height - bitmap->mode_info.height;
  763. y /= 2;
  764. err = grub_video_blit_bitmap (bitmap,
  765. GRUB_VIDEO_BLIT_REPLACE,
  766. x > 0 ? x : 0,
  767. y > 0 ? y : 0,
  768. x < 0 ? -x : 0,
  769. y < 0 ? -y : 0,
  770. min (bitmap->mode_info.width,
  771. mode_info.width),
  772. min (bitmap->mode_info.height,
  773. mode_info.height));
  774. }
  775. if (err)
  776. {
  777. grub_print_error ();
  778. grub_errno = GRUB_ERR_NONE;
  779. bitmap = 0;
  780. }
  781. err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
  782. if (err)
  783. return err;
  784. params->lfb_width = mode_info.width;
  785. params->lfb_height = mode_info.height;
  786. params->lfb_depth = mode_info.bpp;
  787. params->lfb_line_len = mode_info.pitch;
  788. params->lfb_base = (grub_addr_t) framebuffer;
  789. params->lfb_mode = bitmap ? GRUB_XNU_VIDEO_SPLASH
  790. : GRUB_XNU_VIDEO_TEXT_IN_VIDEO;
  791. return GRUB_ERR_NONE;
  792. }
  793. static int
  794. total_ram_hook (grub_uint64_t addr __attribute__ ((unused)), grub_uint64_t size,
  795. grub_memory_type_t type,
  796. void *data)
  797. {
  798. grub_uint64_t *result = data;
  799. if (type != GRUB_MEMORY_AVAILABLE)
  800. return 0;
  801. *result += size;
  802. return 0;
  803. }
  804. static grub_uint64_t
  805. get_total_ram (void)
  806. {
  807. grub_uint64_t result = 0;
  808. grub_mmap_iterate (total_ram_hook, &result);
  809. return result;
  810. }
  811. /* Boot xnu. */
  812. grub_err_t
  813. grub_xnu_boot (void)
  814. {
  815. union grub_xnu_boot_params_any *bootparams;
  816. struct grub_xnu_boot_params_common *bootparams_common;
  817. void *bp_in;
  818. grub_addr_t bootparams_target;
  819. grub_err_t err;
  820. grub_efi_uintn_t memory_map_size = 0;
  821. void *memory_map;
  822. grub_addr_t memory_map_target;
  823. grub_efi_uintn_t map_key = 0;
  824. grub_efi_uintn_t descriptor_size = 0;
  825. grub_efi_uint32_t descriptor_version = 0;
  826. grub_uint64_t firstruntimepage, lastruntimepage;
  827. grub_uint64_t curruntimepage;
  828. grub_addr_t devtree_target;
  829. grub_size_t devtreelen;
  830. int i;
  831. struct grub_relocator32_state state;
  832. grub_uint64_t fsbfreq = 100000000;
  833. int v2 = (grub_xnu_darwin_version >= 11);
  834. grub_uint32_t efi_system_table = 0;
  835. err = grub_autoefi_prepare ();
  836. if (err)
  837. return err;
  838. err = grub_cpu_xnu_fill_devprop ();
  839. if (err)
  840. return err;
  841. err = grub_cpu_xnu_fill_devicetree (&fsbfreq);
  842. if (err)
  843. return err;
  844. err = grub_xnu_fill_devicetree ();
  845. if (err)
  846. return err;
  847. /* Page-align to avoid following parts to be inadvertently freed. */
  848. err = grub_xnu_align_heap (GRUB_XNU_PAGESIZE);
  849. if (err)
  850. return err;
  851. /* Pass memory map to kernel. */
  852. memory_map_size = 0;
  853. memory_map = 0;
  854. map_key = 0;
  855. descriptor_size = 0;
  856. descriptor_version = 0;
  857. grub_dprintf ("xnu", "eip=%x, efi=%p\n", grub_xnu_entry_point,
  858. grub_autoefi_system_table);
  859. const char *debug = grub_env_get ("debug");
  860. if (debug && (grub_strword (debug, "all") || grub_strword (debug, "xnu")))
  861. {
  862. grub_puts_ (N_("Press any key to launch xnu"));
  863. grub_getkey ();
  864. }
  865. /* Relocate the boot parameters to heap. */
  866. err = grub_xnu_heap_malloc (sizeof (*bootparams),
  867. &bp_in, &bootparams_target);
  868. if (err)
  869. return err;
  870. bootparams = bp_in;
  871. grub_memset (bootparams, 0, sizeof (*bootparams));
  872. if (v2)
  873. {
  874. bootparams_common = &bootparams->v2.common;
  875. bootparams->v2.fsbfreq = fsbfreq;
  876. bootparams->v2.ram_size = get_total_ram();
  877. }
  878. else
  879. bootparams_common = &bootparams->v1.common;
  880. /* Set video. */
  881. err = grub_xnu_set_video (bootparams_common);
  882. if (err != GRUB_ERR_NONE)
  883. {
  884. grub_print_error ();
  885. grub_errno = GRUB_ERR_NONE;
  886. grub_puts_ (N_("Booting in blind mode"));
  887. bootparams_common->lfb_mode = 0;
  888. bootparams_common->lfb_width = 0;
  889. bootparams_common->lfb_height = 0;
  890. bootparams_common->lfb_depth = 0;
  891. bootparams_common->lfb_line_len = 0;
  892. bootparams_common->lfb_base = 0;
  893. }
  894. if (grub_autoefi_get_memory_map (&memory_map_size, memory_map,
  895. &map_key, &descriptor_size,
  896. &descriptor_version) < 0)
  897. return grub_errno;
  898. /* We will do few allocations later. Reserve some space for possible
  899. memory map growth. */
  900. memory_map_size += 20 * descriptor_size;
  901. err = grub_xnu_heap_malloc (memory_map_size,
  902. &memory_map, &memory_map_target);
  903. if (err)
  904. return err;
  905. err = grub_xnu_writetree_toheap (&devtree_target, &devtreelen);
  906. if (err)
  907. return err;
  908. grub_memcpy (bootparams_common->cmdline, grub_xnu_cmdline,
  909. sizeof (bootparams_common->cmdline));
  910. bootparams_common->devtree = devtree_target;
  911. bootparams_common->devtreelen = devtreelen;
  912. err = grub_autoefi_finish_boot_services (&memory_map_size, memory_map,
  913. &map_key, &descriptor_size,
  914. &descriptor_version);
  915. if (err)
  916. return err;
  917. if (v2)
  918. bootparams->v2.efi_system_table = (grub_addr_t) grub_autoefi_system_table;
  919. else
  920. bootparams->v1.efi_system_table = (grub_addr_t) grub_autoefi_system_table;
  921. firstruntimepage = (((grub_addr_t) grub_xnu_heap_target_start
  922. + grub_xnu_heap_size + GRUB_XNU_PAGESIZE - 1)
  923. / GRUB_XNU_PAGESIZE) + 20;
  924. curruntimepage = firstruntimepage;
  925. for (i = 0; (unsigned) i < memory_map_size / descriptor_size; i++)
  926. {
  927. grub_efi_memory_descriptor_t *curdesc = (grub_efi_memory_descriptor_t *)
  928. ((char *) memory_map + descriptor_size * i);
  929. curdesc->virtual_start = curdesc->physical_start;
  930. if (curdesc->type == GRUB_EFI_RUNTIME_SERVICES_DATA
  931. || curdesc->type == GRUB_EFI_RUNTIME_SERVICES_CODE)
  932. {
  933. curdesc->virtual_start = curruntimepage << 12;
  934. curruntimepage += curdesc->num_pages;
  935. if (curdesc->physical_start
  936. <= (grub_addr_t) grub_autoefi_system_table
  937. && curdesc->physical_start + (curdesc->num_pages << 12)
  938. > (grub_addr_t) grub_autoefi_system_table)
  939. efi_system_table
  940. = (grub_addr_t) grub_autoefi_system_table
  941. - curdesc->physical_start + curdesc->virtual_start;
  942. if (SIZEOF_OF_UINTN == 8 && grub_xnu_is_64bit)
  943. curdesc->virtual_start |= 0xffffff8000000000ULL;
  944. }
  945. }
  946. lastruntimepage = curruntimepage;
  947. if (v2)
  948. {
  949. bootparams->v2.efi_uintnbits = SIZEOF_OF_UINTN * 8;
  950. bootparams->v2.verminor = GRUB_XNU_BOOTARGSV2_VERMINOR;
  951. bootparams->v2.vermajor = GRUB_XNU_BOOTARGSV2_VERMAJOR;
  952. bootparams->v2.efi_system_table = efi_system_table;
  953. }
  954. else
  955. {
  956. bootparams->v1.efi_uintnbits = SIZEOF_OF_UINTN * 8;
  957. bootparams->v1.verminor = GRUB_XNU_BOOTARGSV1_VERMINOR;
  958. bootparams->v1.vermajor = GRUB_XNU_BOOTARGSV1_VERMAJOR;
  959. bootparams->v1.efi_system_table = efi_system_table;
  960. }
  961. bootparams_common->efi_runtime_first_page = firstruntimepage;
  962. bootparams_common->efi_runtime_npages = lastruntimepage - firstruntimepage;
  963. bootparams_common->efi_mem_desc_size = descriptor_size;
  964. bootparams_common->efi_mem_desc_version = descriptor_version;
  965. bootparams_common->efi_mmap = memory_map_target;
  966. bootparams_common->efi_mmap_size = memory_map_size;
  967. bootparams_common->heap_start = grub_xnu_heap_target_start;
  968. bootparams_common->heap_size = curruntimepage * GRUB_XNU_PAGESIZE - grub_xnu_heap_target_start;
  969. /* Parameters for asm helper. */
  970. grub_xnu_stack = bootparams_common->heap_start
  971. + bootparams_common->heap_size + GRUB_XNU_PAGESIZE;
  972. grub_xnu_arg1 = bootparams_target;
  973. grub_autoefi_set_virtual_address_map (memory_map_size, descriptor_size,
  974. descriptor_version, memory_map);
  975. state.eip = grub_xnu_entry_point;
  976. state.eax = grub_xnu_arg1;
  977. state.esp = grub_xnu_stack;
  978. state.ebp = grub_xnu_stack;
  979. /* XNU uses only APIC. Disable PIC. */
  980. grub_outb (0xff, 0x21);
  981. grub_outb (0xff, 0xa1);
  982. return grub_relocator32_boot (grub_xnu_relocator, state, 0);
  983. }
  984. static grub_command_t cmd_devprop_load;
  985. void
  986. grub_cpu_xnu_init (void)
  987. {
  988. cmd_devprop_load = grub_register_command ("xnu_devprop_load",
  989. grub_cmd_devprop_load,
  990. /* TRANSLATORS: `device-properties'
  991. is a variable name,
  992. not a program. */
  993. 0, N_("Load `device-properties' dump."));
  994. }
  995. void
  996. grub_cpu_xnu_fini (void)
  997. {
  998. grub_unregister_command (cmd_devprop_load);
  999. }