arcdisk.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /* ofdisk.c - Open Firmware disk access. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2004,2006,2007,2008,2009,2011 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/misc.h>
  20. #include <grub/disk.h>
  21. #include <grub/mm.h>
  22. #include <grub/arc/arc.h>
  23. #include <grub/i18n.h>
  24. static grub_arc_fileno_t last_handle = 0;
  25. static char *last_path = NULL;
  26. static int handle_writable = 0;
  27. static int lnum = 0;
  28. struct arcdisk_hash_ent
  29. {
  30. char *devpath;
  31. int num;
  32. struct arcdisk_hash_ent *next;
  33. };
  34. #define ARCDISK_HASH_SZ 8
  35. static struct arcdisk_hash_ent *arcdisk_hash[ARCDISK_HASH_SZ];
  36. static int
  37. arcdisk_hash_fn (const char *devpath)
  38. {
  39. int hash = 0;
  40. while (*devpath)
  41. hash ^= *devpath++;
  42. return (hash & (ARCDISK_HASH_SZ - 1));
  43. }
  44. static struct arcdisk_hash_ent *
  45. arcdisk_hash_find (const char *devpath)
  46. {
  47. struct arcdisk_hash_ent *p = arcdisk_hash[arcdisk_hash_fn (devpath)];
  48. while (p)
  49. {
  50. if (!grub_strcmp (p->devpath, devpath))
  51. break;
  52. p = p->next;
  53. }
  54. return p;
  55. }
  56. static struct arcdisk_hash_ent *
  57. arcdisk_hash_add (char *devpath)
  58. {
  59. struct arcdisk_hash_ent *p;
  60. struct arcdisk_hash_ent **head = &arcdisk_hash[arcdisk_hash_fn(devpath)];
  61. p = grub_malloc (sizeof (*p));
  62. if (!p)
  63. return NULL;
  64. p->devpath = devpath;
  65. p->next = *head;
  66. p->num = lnum++;
  67. *head = p;
  68. return p;
  69. }
  70. /* Context for grub_arcdisk_iterate. */
  71. struct grub_arcdisk_iterate_ctx
  72. {
  73. grub_disk_dev_iterate_hook_t hook;
  74. void *hook_data;
  75. };
  76. /* Helper for grub_arcdisk_iterate. */
  77. static int
  78. grub_arcdisk_iterate_iter (const char *name,
  79. const struct grub_arc_component *comp, void *data)
  80. {
  81. struct grub_arcdisk_iterate_ctx *ctx = data;
  82. if (!(comp->type == GRUB_ARC_COMPONENT_TYPE_DISK
  83. || comp->type == GRUB_ARC_COMPONENT_TYPE_FLOPPY
  84. || comp->type == GRUB_ARC_COMPONENT_TYPE_TAPE))
  85. return 0;
  86. return ctx->hook (name, ctx->hook_data);
  87. }
  88. static int
  89. grub_arcdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
  90. grub_disk_pull_t pull)
  91. {
  92. struct grub_arcdisk_iterate_ctx ctx = { hook, hook_data };
  93. if (pull != GRUB_DISK_PULL_NONE)
  94. return 0;
  95. return grub_arc_iterate_devs (grub_arcdisk_iterate_iter, &ctx, 1);
  96. }
  97. #ifdef GRUB_CPU_MIPSEL
  98. #define RAW_SUFFIX "partition(0)"
  99. #else
  100. #define RAW_SUFFIX "partition(10)"
  101. #endif
  102. static grub_err_t
  103. reopen (const char *name, int writable)
  104. {
  105. grub_arc_fileno_t handle;
  106. if (last_path && grub_strcmp (last_path, name) == 0
  107. && (!writable || handle_writable))
  108. {
  109. grub_dprintf ("arcdisk", "using already opened %s\n", name);
  110. return GRUB_ERR_NONE;
  111. }
  112. if (last_path)
  113. {
  114. GRUB_ARC_FIRMWARE_VECTOR->close (last_handle);
  115. grub_free (last_path);
  116. last_path = NULL;
  117. last_handle = 0;
  118. handle_writable = 0;
  119. }
  120. if (GRUB_ARC_FIRMWARE_VECTOR->open (name,
  121. writable ? GRUB_ARC_FILE_ACCESS_OPEN_RW
  122. : GRUB_ARC_FILE_ACCESS_OPEN_RO, &handle))
  123. {
  124. grub_dprintf ("arcdisk", "couldn't open %s\n", name);
  125. return grub_error (GRUB_ERR_IO, "couldn't open %s", name);
  126. }
  127. handle_writable = writable;
  128. last_path = grub_strdup (name);
  129. if (!last_path)
  130. return grub_errno;
  131. last_handle = handle;
  132. grub_dprintf ("arcdisk", "opened %s\n", name);
  133. return GRUB_ERR_NONE;
  134. }
  135. static grub_err_t
  136. grub_arcdisk_open (const char *name, grub_disk_t disk)
  137. {
  138. char *fullname;
  139. grub_err_t err;
  140. grub_arc_err_t r;
  141. struct grub_arc_fileinfo info;
  142. struct arcdisk_hash_ent *hash;
  143. if (grub_memcmp (name, "arc/", 4) != 0)
  144. return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not arc device");
  145. fullname = grub_arc_alt_name_to_norm (name, RAW_SUFFIX);
  146. disk->data = fullname;
  147. grub_dprintf ("arcdisk", "opening %s\n", fullname);
  148. hash = arcdisk_hash_find (fullname);
  149. if (!hash)
  150. hash = arcdisk_hash_add (fullname);
  151. if (!hash)
  152. return grub_errno;
  153. err = reopen (fullname, 0);
  154. if (err)
  155. return err;
  156. r = GRUB_ARC_FIRMWARE_VECTOR->getfileinformation (last_handle, &info);
  157. if (r)
  158. {
  159. grub_uint64_t res = 0;
  160. int i;
  161. grub_dprintf ("arcdisk", "couldn't retrieve size: %ld\n", r);
  162. for (i = 40; i >= 9; i--)
  163. {
  164. grub_uint64_t pos = res | (1ULL << i);
  165. char buf[512];
  166. long unsigned count = 0;
  167. grub_dprintf ("arcdisk",
  168. "seek to 0x%" PRIxGRUB_UINT64_T "\n", pos);
  169. if (GRUB_ARC_FIRMWARE_VECTOR->seek (last_handle, &pos, 0))
  170. continue;
  171. if (GRUB_ARC_FIRMWARE_VECTOR->read (last_handle, buf,
  172. 0x200, &count))
  173. continue;
  174. if (count == 0)
  175. continue;
  176. res |= (1ULL << i);
  177. }
  178. grub_dprintf ("arcdisk",
  179. "determined disk size 0x%" PRIxGRUB_UINT64_T "\n", res);
  180. disk->total_sectors = (res + 0x200) >> 9;
  181. }
  182. else
  183. disk->total_sectors = (info.end >> 9);
  184. disk->id = hash->num;
  185. return GRUB_ERR_NONE;
  186. }
  187. static void
  188. grub_arcdisk_close (grub_disk_t disk)
  189. {
  190. grub_free (disk->data);
  191. }
  192. static grub_err_t
  193. grub_arcdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
  194. grub_size_t size, char *buf)
  195. {
  196. grub_err_t err;
  197. grub_uint64_t pos = sector << 9;
  198. unsigned long count;
  199. grub_uint64_t totl = size << 9;
  200. grub_arc_err_t r;
  201. err = reopen (disk->data, 0);
  202. if (err)
  203. return err;
  204. r = GRUB_ARC_FIRMWARE_VECTOR->seek (last_handle, &pos, 0);
  205. if (r)
  206. {
  207. grub_dprintf ("arcdisk", "seek to 0x%" PRIxGRUB_UINT64_T " failed: %ld\n",
  208. pos, r);
  209. return grub_error (GRUB_ERR_IO, "couldn't seek");
  210. }
  211. while (totl)
  212. {
  213. if (GRUB_ARC_FIRMWARE_VECTOR->read (last_handle, buf,
  214. totl, &count))
  215. return grub_error (GRUB_ERR_READ_ERROR,
  216. N_("failure reading sector 0x%llx "
  217. "from `%s'"),
  218. (unsigned long long) sector,
  219. disk->name);
  220. totl -= count;
  221. buf += count;
  222. }
  223. return GRUB_ERR_NONE;
  224. }
  225. static grub_err_t
  226. grub_arcdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
  227. grub_size_t size, const char *buf)
  228. {
  229. grub_err_t err;
  230. grub_uint64_t pos = sector << 9;
  231. unsigned long count;
  232. grub_uint64_t totl = size << 9;
  233. grub_arc_err_t r;
  234. err = reopen (disk->data, 1);
  235. if (err)
  236. return err;
  237. r = GRUB_ARC_FIRMWARE_VECTOR->seek (last_handle, &pos, 0);
  238. if (r)
  239. {
  240. grub_dprintf ("arcdisk", "seek to 0x%" PRIxGRUB_UINT64_T " failed: %ld\n",
  241. pos, r);
  242. return grub_error (GRUB_ERR_IO, "couldn't seek");
  243. }
  244. while (totl)
  245. {
  246. if (GRUB_ARC_FIRMWARE_VECTOR->write (last_handle, buf,
  247. totl, &count))
  248. return grub_error (GRUB_ERR_WRITE_ERROR, N_("failure writing sector 0x%llx "
  249. "to `%s'"),
  250. (unsigned long long) sector,
  251. disk->name);
  252. totl -= count;
  253. buf += count;
  254. }
  255. return GRUB_ERR_NONE;
  256. }
  257. static struct grub_disk_dev grub_arcdisk_dev =
  258. {
  259. .name = "arcdisk",
  260. .id = GRUB_DISK_DEVICE_ARCDISK_ID,
  261. .disk_iterate = grub_arcdisk_iterate,
  262. .disk_open = grub_arcdisk_open,
  263. .disk_close = grub_arcdisk_close,
  264. .disk_read = grub_arcdisk_read,
  265. .disk_write = grub_arcdisk_write,
  266. .next = 0
  267. };
  268. void
  269. grub_arcdisk_init (void)
  270. {
  271. grub_disk_dev_register (&grub_arcdisk_dev);
  272. }
  273. void
  274. grub_arcdisk_fini (void)
  275. {
  276. if (last_path)
  277. {
  278. GRUB_ARC_FIRMWARE_VECTOR->close (last_handle);
  279. grub_free (last_path);
  280. last_path = NULL;
  281. last_handle = 0;
  282. }
  283. grub_disk_dev_unregister (&grub_arcdisk_dev);
  284. }