efidisk.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2006,2007,2008 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/disk.h>
  19. #include <grub/partition.h>
  20. #include <grub/mm.h>
  21. #include <grub/types.h>
  22. #include <grub/misc.h>
  23. #include <grub/err.h>
  24. #include <grub/term.h>
  25. #include <grub/efi/api.h>
  26. #include <grub/efi/efi.h>
  27. #include <grub/efi/disk.h>
  28. struct grub_efidisk_data
  29. {
  30. grub_efi_handle_t handle;
  31. grub_efi_device_path_t *device_path;
  32. grub_efi_device_path_t *last_device_path;
  33. grub_efi_block_io_t *block_io;
  34. struct grub_efidisk_data *next;
  35. };
  36. /* GUID. */
  37. static grub_guid_t block_io_guid = GRUB_EFI_BLOCK_IO_GUID;
  38. static struct grub_efidisk_data *fd_devices;
  39. static struct grub_efidisk_data *hd_devices;
  40. static struct grub_efidisk_data *cd_devices;
  41. static struct grub_efidisk_data *
  42. make_devices (void)
  43. {
  44. grub_efi_uintn_t num_handles;
  45. grub_efi_handle_t *handles;
  46. grub_efi_handle_t *handle;
  47. struct grub_efidisk_data *devices = 0;
  48. /* Find handles which support the disk io interface. */
  49. handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &block_io_guid,
  50. 0, &num_handles);
  51. if (! handles)
  52. return 0;
  53. /* Make a linked list of devices. */
  54. for (handle = handles; num_handles--; handle++)
  55. {
  56. grub_efi_device_path_t *dp;
  57. grub_efi_device_path_t *ldp;
  58. struct grub_efidisk_data *d;
  59. grub_efi_block_io_t *bio;
  60. dp = grub_efi_get_device_path (*handle);
  61. if (! dp)
  62. continue;
  63. ldp = grub_efi_find_last_device_path (dp);
  64. if (! ldp)
  65. /* This is empty. Why? */
  66. continue;
  67. bio = grub_efi_open_protocol (*handle, &block_io_guid,
  68. GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  69. if (! bio)
  70. /* This should not happen... Why? */
  71. continue;
  72. /* iPXE adds stub Block IO protocol to loaded image device handle. It is
  73. completely non-functional and simply returns an error for every method.
  74. So attempt to detect and skip it. Magic number is literal "iPXE" and
  75. check block size as well */
  76. /* FIXME: shoud we close it? We do not do it elsewhere */
  77. if (bio->media && bio->media->media_id == 0x69505845U &&
  78. bio->media->block_size == 1)
  79. continue;
  80. d = grub_malloc (sizeof (*d));
  81. if (! d)
  82. {
  83. /* Uggh. */
  84. grub_free (handles);
  85. while (devices)
  86. {
  87. d = devices->next;
  88. grub_free (devices);
  89. devices = d;
  90. }
  91. return 0;
  92. }
  93. d->handle = *handle;
  94. d->device_path = dp;
  95. d->last_device_path = ldp;
  96. d->block_io = bio;
  97. d->next = devices;
  98. devices = d;
  99. }
  100. grub_free (handles);
  101. return devices;
  102. }
  103. /* Find the parent device. */
  104. static struct grub_efidisk_data *
  105. find_parent_device (struct grub_efidisk_data *devices,
  106. struct grub_efidisk_data *d)
  107. {
  108. grub_efi_device_path_t *dp, *ldp;
  109. struct grub_efidisk_data *parent;
  110. dp = grub_efi_duplicate_device_path (d->device_path);
  111. if (! dp)
  112. return 0;
  113. ldp = grub_efi_find_last_device_path (dp);
  114. if (! ldp)
  115. return 0;
  116. ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
  117. ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
  118. ldp->length = sizeof (*ldp);
  119. for (parent = devices; parent; parent = parent->next)
  120. {
  121. /* Ignore itself. */
  122. if (parent == d)
  123. continue;
  124. if (grub_efi_compare_device_paths (parent->device_path, dp) == 0)
  125. break;
  126. }
  127. grub_free (dp);
  128. return parent;
  129. }
  130. static int
  131. is_child (struct grub_efidisk_data *child,
  132. struct grub_efidisk_data *parent)
  133. {
  134. grub_efi_device_path_t *dp, *ldp;
  135. int ret;
  136. dp = grub_efi_duplicate_device_path (child->device_path);
  137. if (! dp)
  138. return 0;
  139. ldp = grub_efi_find_last_device_path (dp);
  140. if (! ldp)
  141. return 0;
  142. ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
  143. ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
  144. ldp->length = sizeof (*ldp);
  145. ret = (grub_efi_compare_device_paths (dp, parent->device_path) == 0);
  146. grub_free (dp);
  147. return ret;
  148. }
  149. #define FOR_CHILDREN(p, dev) for (p = dev; p; p = p->next) if (is_child (p, d))
  150. /* Add a device into a list of devices in an ascending order. */
  151. static void
  152. add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d)
  153. {
  154. struct grub_efidisk_data **p;
  155. struct grub_efidisk_data *n;
  156. for (p = devices; *p; p = &((*p)->next))
  157. {
  158. int ret;
  159. ret = grub_efi_compare_device_paths (grub_efi_find_last_device_path ((*p)->device_path),
  160. grub_efi_find_last_device_path (d->device_path));
  161. if (ret == 0)
  162. ret = grub_efi_compare_device_paths ((*p)->device_path,
  163. d->device_path);
  164. if (ret == 0)
  165. return;
  166. else if (ret > 0)
  167. break;
  168. }
  169. n = grub_malloc (sizeof (*n));
  170. if (! n)
  171. return;
  172. grub_memcpy (n, d, sizeof (*n));
  173. n->next = (*p);
  174. (*p) = n;
  175. }
  176. /* Name the devices. */
  177. static void
  178. name_devices (struct grub_efidisk_data *devices)
  179. {
  180. struct grub_efidisk_data *d;
  181. /* First, identify devices by media device paths. */
  182. for (d = devices; d; d = d->next)
  183. {
  184. grub_efi_device_path_t *dp;
  185. dp = d->last_device_path;
  186. if (! dp)
  187. continue;
  188. if (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
  189. {
  190. int is_hard_drive = 0;
  191. switch (GRUB_EFI_DEVICE_PATH_SUBTYPE (dp))
  192. {
  193. case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE:
  194. is_hard_drive = 1;
  195. /* Intentionally fall through. */
  196. case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE:
  197. {
  198. struct grub_efidisk_data *parent, *parent2;
  199. parent = find_parent_device (devices, d);
  200. if (!parent)
  201. {
  202. #ifdef DEBUG_NAMES
  203. grub_printf ("skipping orphaned partition: ");
  204. grub_efi_print_device_path (d->device_path);
  205. #endif
  206. break;
  207. }
  208. parent2 = find_parent_device (devices, parent);
  209. if (parent2)
  210. {
  211. #ifdef DEBUG_NAMES
  212. grub_printf ("skipping subpartition: ");
  213. grub_efi_print_device_path (d->device_path);
  214. #endif
  215. /* Mark itself as used. */
  216. d->last_device_path = 0;
  217. break;
  218. }
  219. if (!parent->last_device_path)
  220. {
  221. d->last_device_path = 0;
  222. break;
  223. }
  224. if (is_hard_drive)
  225. {
  226. #ifdef DEBUG_NAMES
  227. grub_printf ("adding a hard drive by a partition: ");
  228. grub_efi_print_device_path (parent->device_path);
  229. #endif
  230. add_device (&hd_devices, parent);
  231. }
  232. else
  233. {
  234. #ifdef DEBUG_NAMES
  235. grub_printf ("adding a cdrom by a partition: ");
  236. grub_efi_print_device_path (parent->device_path);
  237. #endif
  238. add_device (&cd_devices, parent);
  239. }
  240. /* Mark the parent as used. */
  241. parent->last_device_path = 0;
  242. }
  243. /* Mark itself as used. */
  244. d->last_device_path = 0;
  245. break;
  246. default:
  247. #ifdef DEBUG_NAMES
  248. grub_printf ("skipping other type: ");
  249. grub_efi_print_device_path (d->device_path);
  250. #endif
  251. /* For now, ignore the others. */
  252. break;
  253. }
  254. }
  255. else
  256. {
  257. #ifdef DEBUG_NAMES
  258. grub_printf ("skipping non-media: ");
  259. grub_efi_print_device_path (d->device_path);
  260. #endif
  261. }
  262. }
  263. /* Let's see what can be added more. */
  264. for (d = devices; d; d = d->next)
  265. {
  266. grub_efi_device_path_t *dp;
  267. grub_efi_block_io_media_t *m;
  268. int is_floppy = 0;
  269. dp = d->last_device_path;
  270. if (! dp)
  271. continue;
  272. /* Ghosts proudly presented by Apple. */
  273. if (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
  274. && GRUB_EFI_DEVICE_PATH_SUBTYPE (dp)
  275. == GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE)
  276. {
  277. grub_efi_vendor_device_path_t *vendor = (grub_efi_vendor_device_path_t *) dp;
  278. static const grub_guid_t apple = GRUB_EFI_VENDOR_APPLE_GUID;
  279. if (vendor->header.length == sizeof (*vendor)
  280. && grub_memcmp (&vendor->vendor_guid, &apple,
  281. sizeof (vendor->vendor_guid)) == 0
  282. && find_parent_device (devices, d))
  283. continue;
  284. }
  285. m = d->block_io->media;
  286. if (GRUB_EFI_DEVICE_PATH_TYPE (dp) == GRUB_EFI_ACPI_DEVICE_PATH_TYPE
  287. && GRUB_EFI_DEVICE_PATH_SUBTYPE (dp)
  288. == GRUB_EFI_ACPI_DEVICE_PATH_SUBTYPE)
  289. {
  290. grub_efi_acpi_device_path_t *acpi
  291. = (grub_efi_acpi_device_path_t *) dp;
  292. /* Floppy EISA ID. */
  293. if (acpi->hid == 0x60441d0 || acpi->hid == 0x70041d0
  294. || acpi->hid == 0x70141d1)
  295. is_floppy = 1;
  296. }
  297. if (is_floppy)
  298. {
  299. #ifdef DEBUG_NAMES
  300. grub_printf ("adding a floppy: ");
  301. grub_efi_print_device_path (d->device_path);
  302. #endif
  303. add_device (&fd_devices, d);
  304. }
  305. else if (m->read_only && m->block_size > GRUB_DISK_SECTOR_SIZE)
  306. {
  307. /* This check is too heuristic, but assume that this is a
  308. CDROM drive. */
  309. #ifdef DEBUG_NAMES
  310. grub_printf ("adding a cdrom by guessing: ");
  311. grub_efi_print_device_path (d->device_path);
  312. #endif
  313. add_device (&cd_devices, d);
  314. }
  315. else
  316. {
  317. /* The default is a hard drive. */
  318. #ifdef DEBUG_NAMES
  319. grub_printf ("adding a hard drive by guessing: ");
  320. grub_efi_print_device_path (d->device_path);
  321. #endif
  322. add_device (&hd_devices, d);
  323. }
  324. }
  325. }
  326. static void
  327. free_devices (struct grub_efidisk_data *devices)
  328. {
  329. struct grub_efidisk_data *p, *q;
  330. for (p = devices; p; p = q)
  331. {
  332. q = p->next;
  333. grub_free (p);
  334. }
  335. }
  336. /* Enumerate all disks to name devices. */
  337. static void
  338. enumerate_disks (void)
  339. {
  340. struct grub_efidisk_data *devices;
  341. devices = make_devices ();
  342. if (! devices)
  343. return;
  344. name_devices (devices);
  345. free_devices (devices);
  346. }
  347. static int
  348. grub_efidisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
  349. grub_disk_pull_t pull)
  350. {
  351. struct grub_efidisk_data *d;
  352. char buf[16];
  353. int count;
  354. switch (pull)
  355. {
  356. case GRUB_DISK_PULL_NONE:
  357. for (d = hd_devices, count = 0; d; d = d->next, count++)
  358. {
  359. grub_snprintf (buf, sizeof (buf), "hd%d", count);
  360. grub_dprintf ("efidisk", "iterating %s\n", buf);
  361. if (hook (buf, hook_data))
  362. return 1;
  363. }
  364. break;
  365. case GRUB_DISK_PULL_REMOVABLE:
  366. for (d = fd_devices, count = 0; d; d = d->next, count++)
  367. {
  368. grub_snprintf (buf, sizeof (buf), "fd%d", count);
  369. grub_dprintf ("efidisk", "iterating %s\n", buf);
  370. if (hook (buf, hook_data))
  371. return 1;
  372. }
  373. for (d = cd_devices, count = 0; d; d = d->next, count++)
  374. {
  375. grub_snprintf (buf, sizeof (buf), "cd%d", count);
  376. grub_dprintf ("efidisk", "iterating %s\n", buf);
  377. if (hook (buf, hook_data))
  378. return 1;
  379. }
  380. break;
  381. default:
  382. return 0;
  383. }
  384. return 0;
  385. }
  386. static int
  387. get_drive_number (const char *name)
  388. {
  389. unsigned long drive;
  390. if ((name[0] != 'f' && name[0] != 'h' && name[0] != 'c') || name[1] != 'd')
  391. goto fail;
  392. drive = grub_strtoul (name + 2, 0, 10);
  393. if (grub_errno != GRUB_ERR_NONE)
  394. goto fail;
  395. return (int) drive ;
  396. fail:
  397. grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a efidisk");
  398. return -1;
  399. }
  400. static struct grub_efidisk_data *
  401. get_device (struct grub_efidisk_data *devices, int num)
  402. {
  403. struct grub_efidisk_data *d;
  404. for (d = devices; d && num; d = d->next, num--)
  405. ;
  406. if (num == 0)
  407. return d;
  408. return 0;
  409. }
  410. static grub_err_t
  411. grub_efidisk_open (const char *name, struct grub_disk *disk)
  412. {
  413. int num;
  414. struct grub_efidisk_data *d = 0;
  415. grub_efi_block_io_media_t *m;
  416. grub_dprintf ("efidisk", "opening %s\n", name);
  417. num = get_drive_number (name);
  418. if (num < 0)
  419. return grub_errno;
  420. switch (name[0])
  421. {
  422. case 'f':
  423. d = get_device (fd_devices, num);
  424. break;
  425. case 'c':
  426. d = get_device (cd_devices, num);
  427. break;
  428. case 'h':
  429. d = get_device (hd_devices, num);
  430. break;
  431. default:
  432. /* Never reach here. */
  433. break;
  434. }
  435. if (! d)
  436. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such device");
  437. disk->id = ((num << GRUB_CHAR_BIT) | name[0]);
  438. m = d->block_io->media;
  439. /* FIXME: Probably it is better to store the block size in the disk,
  440. and total sectors should be replaced with total blocks. */
  441. grub_dprintf ("efidisk",
  442. "m = %p, last block = %llx, block size = %x, io align = %x\n",
  443. m, (unsigned long long) m->last_block, m->block_size,
  444. m->io_align);
  445. /* Ensure required buffer alignment is a power of two (or is zero). */
  446. if (m->io_align & (m->io_align - 1))
  447. return grub_error (GRUB_ERR_IO, "invalid buffer alignment %d", m->io_align);
  448. disk->total_sectors = m->last_block + 1;
  449. /* Don't increase this value due to bug in some EFI. */
  450. disk->max_agglomerate = 0xa0000 >> (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS);
  451. if (m->block_size & (m->block_size - 1) || !m->block_size)
  452. return grub_error (GRUB_ERR_IO, "invalid sector size %d",
  453. m->block_size);
  454. disk->log_sector_size = grub_log2ull (m->block_size);
  455. disk->data = d;
  456. grub_dprintf ("efidisk", "opening %s succeeded\n", name);
  457. return GRUB_ERR_NONE;
  458. }
  459. static void
  460. grub_efidisk_close (struct grub_disk *disk __attribute__ ((unused)))
  461. {
  462. /* EFI disks do not allocate extra memory, so nothing to do here. */
  463. grub_dprintf ("efidisk", "closing %s\n", disk->name);
  464. }
  465. static grub_efi_status_t
  466. grub_efidisk_readwrite (struct grub_disk *disk, grub_disk_addr_t sector,
  467. grub_size_t size, char *buf, int wr)
  468. {
  469. struct grub_efidisk_data *d;
  470. grub_efi_block_io_t *bio;
  471. grub_efi_status_t status;
  472. grub_size_t io_align, num_bytes;
  473. char *aligned_buf;
  474. d = disk->data;
  475. bio = d->block_io;
  476. /*
  477. * If IoAlign is > 1, it should represent the required alignment. However,
  478. * some UEFI implementations seem to report IoAlign=2 but require 2^IoAlign.
  479. * Some implementation seem to require alignment despite not reporting any
  480. * specific requirements.
  481. *
  482. * Make sure to use buffers which are at least aligned to block size.
  483. */
  484. if (bio->media->io_align < bio->media->block_size)
  485. io_align = bio->media->block_size;
  486. else
  487. io_align = bio->media->io_align;
  488. num_bytes = size << disk->log_sector_size;
  489. if ((grub_addr_t) buf & (io_align - 1))
  490. {
  491. aligned_buf = grub_memalign (io_align, num_bytes);
  492. if (! aligned_buf)
  493. return GRUB_EFI_OUT_OF_RESOURCES;
  494. if (wr)
  495. grub_memcpy (aligned_buf, buf, num_bytes);
  496. }
  497. else
  498. {
  499. aligned_buf = buf;
  500. }
  501. status = (wr ? bio->write_blocks : bio->read_blocks) (bio, bio->media->media_id,
  502. (grub_efi_uint64_t) sector,
  503. (grub_efi_uintn_t) num_bytes,
  504. aligned_buf);
  505. if ((grub_addr_t) buf & (io_align - 1))
  506. {
  507. if (!wr)
  508. grub_memcpy (buf, aligned_buf, num_bytes);
  509. grub_free (aligned_buf);
  510. }
  511. return status;
  512. }
  513. static grub_err_t
  514. grub_efidisk_read (struct grub_disk *disk, grub_disk_addr_t sector,
  515. grub_size_t size, char *buf)
  516. {
  517. grub_efi_status_t status;
  518. grub_dprintf ("efidisk",
  519. "reading 0x%lx sectors at the sector 0x%llx from %s\n",
  520. (unsigned long) size, (unsigned long long) sector, disk->name);
  521. status = grub_efidisk_readwrite (disk, sector, size, buf, 0);
  522. if (status == GRUB_EFI_NO_MEDIA)
  523. return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("no media in `%s'"), disk->name);
  524. else if (status != GRUB_EFI_SUCCESS)
  525. return grub_error (GRUB_ERR_READ_ERROR,
  526. N_("failure reading sector 0x%llx from `%s'"),
  527. (unsigned long long) sector,
  528. disk->name);
  529. return GRUB_ERR_NONE;
  530. }
  531. static grub_err_t
  532. grub_efidisk_write (struct grub_disk *disk, grub_disk_addr_t sector,
  533. grub_size_t size, const char *buf)
  534. {
  535. grub_efi_status_t status;
  536. grub_dprintf ("efidisk",
  537. "writing 0x%lx sectors at the sector 0x%llx to %s\n",
  538. (unsigned long) size, (unsigned long long) sector, disk->name);
  539. status = grub_efidisk_readwrite (disk, sector, size, (char *) buf, 1);
  540. if (status == GRUB_EFI_NO_MEDIA)
  541. return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("no media in `%s'"), disk->name);
  542. else if (status != GRUB_EFI_SUCCESS)
  543. return grub_error (GRUB_ERR_WRITE_ERROR,
  544. N_("failure writing sector 0x%llx to `%s'"),
  545. (unsigned long long) sector, disk->name);
  546. return GRUB_ERR_NONE;
  547. }
  548. static struct grub_disk_dev grub_efidisk_dev =
  549. {
  550. .name = "efidisk",
  551. .id = GRUB_DISK_DEVICE_EFIDISK_ID,
  552. .disk_iterate = grub_efidisk_iterate,
  553. .disk_open = grub_efidisk_open,
  554. .disk_close = grub_efidisk_close,
  555. .disk_read = grub_efidisk_read,
  556. .disk_write = grub_efidisk_write,
  557. .next = 0
  558. };
  559. void
  560. grub_efidisk_fini (void)
  561. {
  562. free_devices (fd_devices);
  563. free_devices (hd_devices);
  564. free_devices (cd_devices);
  565. fd_devices = 0;
  566. hd_devices = 0;
  567. cd_devices = 0;
  568. grub_disk_dev_unregister (&grub_efidisk_dev);
  569. }
  570. void
  571. grub_efidisk_init (void)
  572. {
  573. grub_disk_firmware_fini = grub_efidisk_fini;
  574. enumerate_disks ();
  575. grub_disk_dev_register (&grub_efidisk_dev);
  576. }
  577. /* Some utility functions to map GRUB devices with EFI devices. */
  578. grub_efi_handle_t
  579. grub_efidisk_get_device_handle (grub_disk_t disk)
  580. {
  581. struct grub_efidisk_data *d;
  582. char type;
  583. if (disk->dev->id != GRUB_DISK_DEVICE_EFIDISK_ID)
  584. return 0;
  585. d = disk->data;
  586. type = disk->name[0];
  587. switch (type)
  588. {
  589. case 'f':
  590. /* This is the simplest case. */
  591. return d->handle;
  592. case 'c':
  593. /* FIXME: probably this is not correct. */
  594. return d->handle;
  595. case 'h':
  596. /* If this is the whole disk, just return its own data. */
  597. if (! disk->partition)
  598. return d->handle;
  599. /* Otherwise, we must query the corresponding device to the firmware. */
  600. {
  601. struct grub_efidisk_data *devices;
  602. grub_efi_handle_t handle = 0;
  603. struct grub_efidisk_data *c;
  604. devices = make_devices ();
  605. FOR_CHILDREN (c, devices)
  606. {
  607. grub_efi_hard_drive_device_path_t *hd;
  608. hd = (grub_efi_hard_drive_device_path_t *) c->last_device_path;
  609. if ((GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path)
  610. == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
  611. && (GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path)
  612. == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)
  613. && (grub_partition_get_start (disk->partition)
  614. == (hd->partition_start << (disk->log_sector_size
  615. - GRUB_DISK_SECTOR_BITS)))
  616. && (grub_partition_get_len (disk->partition)
  617. == (hd->partition_size << (disk->log_sector_size
  618. - GRUB_DISK_SECTOR_BITS))))
  619. {
  620. handle = c->handle;
  621. break;
  622. }
  623. }
  624. free_devices (devices);
  625. if (handle != 0)
  626. return handle;
  627. }
  628. break;
  629. default:
  630. break;
  631. }
  632. return 0;
  633. }
  634. #define NEEDED_BUFLEN sizeof ("XdXXXXXXXXXX")
  635. static inline int
  636. get_diskname_from_path_real (const grub_efi_device_path_t *path,
  637. struct grub_efidisk_data *head,
  638. char *buf)
  639. {
  640. int count = 0;
  641. struct grub_efidisk_data *d;
  642. for (d = head, count = 0; d; d = d->next, count++)
  643. if (grub_efi_compare_device_paths (d->device_path, path) == 0)
  644. {
  645. grub_snprintf (buf, NEEDED_BUFLEN - 1, "d%d", count);
  646. return 1;
  647. }
  648. return 0;
  649. }
  650. static inline int
  651. get_diskname_from_path (const grub_efi_device_path_t *path,
  652. char *buf)
  653. {
  654. if (get_diskname_from_path_real (path, hd_devices, buf + 1))
  655. {
  656. buf[0] = 'h';
  657. return 1;
  658. }
  659. if (get_diskname_from_path_real (path, fd_devices, buf + 1))
  660. {
  661. buf[0] = 'f';
  662. return 1;
  663. }
  664. if (get_diskname_from_path_real (path, cd_devices, buf + 1))
  665. {
  666. buf[0] = 'c';
  667. return 1;
  668. }
  669. return 0;
  670. }
  671. /* Context for grub_efidisk_get_device_name. */
  672. struct grub_efidisk_get_device_name_ctx
  673. {
  674. char *partition_name;
  675. grub_efi_hard_drive_device_path_t *hd;
  676. };
  677. /* Helper for grub_efidisk_get_device_name.
  678. Find the identical partition. */
  679. static int
  680. grub_efidisk_get_device_name_iter (grub_disk_t disk,
  681. const grub_partition_t part, void *data)
  682. {
  683. struct grub_efidisk_get_device_name_ctx *ctx = data;
  684. if (grub_partition_get_start (part)
  685. == (ctx->hd->partition_start << (disk->log_sector_size
  686. - GRUB_DISK_SECTOR_BITS))
  687. && grub_partition_get_len (part)
  688. == (ctx->hd->partition_size << (disk->log_sector_size
  689. - GRUB_DISK_SECTOR_BITS)))
  690. {
  691. ctx->partition_name = grub_partition_get_name (part);
  692. return 1;
  693. }
  694. return 0;
  695. }
  696. char *
  697. grub_efidisk_get_device_name (grub_efi_handle_t *handle)
  698. {
  699. grub_efi_device_path_t *dp, *ldp;
  700. char device_name[NEEDED_BUFLEN];
  701. dp = grub_efi_get_device_path (handle);
  702. if (! dp)
  703. return 0;
  704. ldp = grub_efi_find_last_device_path (dp);
  705. if (! ldp)
  706. return 0;
  707. if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
  708. && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE
  709. || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
  710. {
  711. struct grub_efidisk_get_device_name_ctx ctx;
  712. char *dev_name;
  713. grub_efi_device_path_t *dup_dp;
  714. grub_disk_t parent = 0;
  715. /* It is necessary to duplicate the device path so that GRUB
  716. can overwrite it. */
  717. dup_dp = grub_efi_duplicate_device_path (dp);
  718. if (! dup_dp)
  719. return 0;
  720. while (1)
  721. {
  722. grub_efi_device_path_t *dup_ldp;
  723. dup_ldp = grub_efi_find_last_device_path (dup_dp);
  724. if (! dup_ldp)
  725. break;
  726. if (!(GRUB_EFI_DEVICE_PATH_TYPE (dup_ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
  727. && (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE
  728. || GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)))
  729. break;
  730. dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
  731. dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
  732. dup_ldp->length = sizeof (*dup_ldp);
  733. }
  734. if (!get_diskname_from_path (dup_dp, device_name))
  735. {
  736. grub_free (dup_dp);
  737. return 0;
  738. }
  739. parent = grub_disk_open (device_name);
  740. grub_free (dup_dp);
  741. if (! parent)
  742. return 0;
  743. /* Find a partition which matches the hard drive device path. */
  744. ctx.partition_name = NULL;
  745. ctx.hd = (grub_efi_hard_drive_device_path_t *) ldp;
  746. if (ctx.hd->partition_start == 0
  747. && (ctx.hd->partition_size << (parent->log_sector_size
  748. - GRUB_DISK_SECTOR_BITS))
  749. == grub_disk_native_sectors (parent))
  750. {
  751. dev_name = grub_strdup (parent->name);
  752. }
  753. else
  754. {
  755. grub_partition_iterate (parent, grub_efidisk_get_device_name_iter,
  756. &ctx);
  757. if (! ctx.partition_name)
  758. {
  759. /* No partition found. In most cases partition is embed in
  760. the root path anyway, so this is not critical.
  761. This happens only if partition is on partmap that GRUB
  762. doesn't need to access root.
  763. */
  764. grub_disk_close (parent);
  765. return grub_strdup (device_name);
  766. }
  767. dev_name = grub_xasprintf ("%s,%s", parent->name,
  768. ctx.partition_name);
  769. grub_free (ctx.partition_name);
  770. }
  771. grub_disk_close (parent);
  772. return dev_name;
  773. }
  774. /* This may be guessed device - floppy, cdrom or entire disk. */
  775. if (!get_diskname_from_path (dp, device_name))
  776. return 0;
  777. return grub_strdup (device_name);
  778. }