bootmeth-uclass.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2021 Google LLC
  4. * Written by Simon Glass <sjg@chromium.org>
  5. */
  6. #define LOG_CATEGORY UCLASS_BOOTSTD
  7. #include <common.h>
  8. #include <blk.h>
  9. #include <bootflow.h>
  10. #include <bootmeth.h>
  11. #include <bootstd.h>
  12. #include <dm.h>
  13. #include <env_internal.h>
  14. #include <fs.h>
  15. #include <malloc.h>
  16. #include <mapmem.h>
  17. #include <dm/uclass-internal.h>
  18. DECLARE_GLOBAL_DATA_PTR;
  19. int bootmeth_get_state_desc(struct udevice *dev, char *buf, int maxsize)
  20. {
  21. const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
  22. if (!ops->get_state_desc)
  23. return -ENOSYS;
  24. return ops->get_state_desc(dev, buf, maxsize);
  25. }
  26. int bootmeth_check(struct udevice *dev, struct bootflow_iter *iter)
  27. {
  28. const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
  29. if (!ops->check)
  30. return 0;
  31. return ops->check(dev, iter);
  32. }
  33. int bootmeth_read_bootflow(struct udevice *dev, struct bootflow *bflow)
  34. {
  35. const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
  36. if (!ops->read_bootflow)
  37. return -ENOSYS;
  38. return ops->read_bootflow(dev, bflow);
  39. }
  40. int bootmeth_set_bootflow(struct udevice *dev, struct bootflow *bflow,
  41. char *buf, int size)
  42. {
  43. const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
  44. if (!ops->set_bootflow)
  45. return -ENOSYS;
  46. return ops->set_bootflow(dev, bflow, buf, size);
  47. }
  48. int bootmeth_boot(struct udevice *dev, struct bootflow *bflow)
  49. {
  50. const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
  51. if (!ops->boot)
  52. return -ENOSYS;
  53. return ops->boot(dev, bflow);
  54. }
  55. int bootmeth_read_file(struct udevice *dev, struct bootflow *bflow,
  56. const char *file_path, ulong addr, ulong *sizep)
  57. {
  58. const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
  59. if (!ops->read_file)
  60. return -ENOSYS;
  61. return ops->read_file(dev, bflow, file_path, addr, sizep);
  62. }
  63. int bootmeth_get_bootflow(struct udevice *dev, struct bootflow *bflow)
  64. {
  65. const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
  66. if (!ops->read_bootflow)
  67. return -ENOSYS;
  68. bootflow_init(bflow, NULL, dev);
  69. return ops->read_bootflow(dev, bflow);
  70. }
  71. int bootmeth_setup_iter_order(struct bootflow_iter *iter, bool include_global)
  72. {
  73. struct bootstd_priv *std;
  74. struct udevice **order;
  75. int count;
  76. int ret;
  77. ret = bootstd_get_priv(&std);
  78. if (ret)
  79. return ret;
  80. /* Create an array large enough */
  81. count = std->bootmeth_count ? std->bootmeth_count :
  82. uclass_id_count(UCLASS_BOOTMETH);
  83. if (!count)
  84. return log_msg_ret("count", -ENOENT);
  85. order = calloc(count, sizeof(struct udevice *));
  86. if (!order)
  87. return log_msg_ret("order", -ENOMEM);
  88. /* If we have an ordering, copy it */
  89. if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && std->bootmeth_count) {
  90. int i;
  91. /*
  92. * We don't support skipping global bootmeths. Instead, the user
  93. * should omit them from the ordering
  94. */
  95. if (!include_global)
  96. return log_msg_ret("glob", -EPERM);
  97. memcpy(order, std->bootmeth_order,
  98. count * sizeof(struct bootmeth *));
  99. if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL)) {
  100. for (i = 0; i < count; i++) {
  101. struct udevice *dev = order[i];
  102. struct bootmeth_uc_plat *ucp;
  103. bool is_global;
  104. ucp = dev_get_uclass_plat(dev);
  105. is_global = ucp->flags &
  106. BOOTMETHF_GLOBAL;
  107. if (is_global) {
  108. iter->first_glob_method = i;
  109. break;
  110. }
  111. }
  112. }
  113. } else {
  114. struct udevice *dev;
  115. int i, upto, pass;
  116. /*
  117. * Do two passes, one to find the normal bootmeths and another
  118. * to find the global ones, if required, The global ones go at
  119. * the end.
  120. */
  121. for (pass = 0, upto = 0; pass < 1 + include_global; pass++) {
  122. if (pass)
  123. iter->first_glob_method = upto;
  124. /*
  125. * Get a list of bootmethods, in seq order (i.e. using
  126. * aliases). There may be gaps so try to count up high
  127. * enough to find them all.
  128. */
  129. for (i = 0; upto < count && i < 20 + count * 2; i++) {
  130. struct bootmeth_uc_plat *ucp;
  131. bool is_global;
  132. ret = uclass_get_device_by_seq(UCLASS_BOOTMETH,
  133. i, &dev);
  134. if (ret)
  135. continue;
  136. ucp = dev_get_uclass_plat(dev);
  137. is_global =
  138. IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) &&
  139. (ucp->flags & BOOTMETHF_GLOBAL);
  140. if (pass ? is_global : !is_global)
  141. order[upto++] = dev;
  142. }
  143. }
  144. count = upto;
  145. }
  146. if (!count)
  147. return log_msg_ret("count2", -ENOENT);
  148. if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && include_global &&
  149. iter->first_glob_method != -1 && iter->first_glob_method != count) {
  150. iter->cur_method = iter->first_glob_method;
  151. iter->doing_global = true;
  152. }
  153. iter->method_order = order;
  154. iter->num_methods = count;
  155. return 0;
  156. }
  157. int bootmeth_set_order(const char *order_str)
  158. {
  159. struct bootstd_priv *std;
  160. struct udevice **order;
  161. int count, ret, i, len;
  162. const char *s, *p;
  163. ret = bootstd_get_priv(&std);
  164. if (ret)
  165. return ret;
  166. if (!order_str) {
  167. free(std->bootmeth_order);
  168. std->bootmeth_order = NULL;
  169. std->bootmeth_count = 0;
  170. return 0;
  171. }
  172. /* Create an array large enough */
  173. count = uclass_id_count(UCLASS_BOOTMETH);
  174. if (!count)
  175. return log_msg_ret("count", -ENOENT);
  176. order = calloc(count + 1, sizeof(struct udevice *));
  177. if (!order)
  178. return log_msg_ret("order", -ENOMEM);
  179. for (i = 0, s = order_str; *s && i < count; s = p + (*p == ' '), i++) {
  180. struct udevice *dev;
  181. p = strchrnul(s, ' ');
  182. len = p - s;
  183. ret = uclass_find_device_by_namelen(UCLASS_BOOTMETH, s, len,
  184. &dev);
  185. if (ret) {
  186. printf("Unknown bootmeth '%.*s'\n", len, s);
  187. free(order);
  188. return ret;
  189. }
  190. order[i] = dev;
  191. }
  192. order[i] = NULL;
  193. free(std->bootmeth_order);
  194. std->bootmeth_order = order;
  195. std->bootmeth_count = i;
  196. return 0;
  197. }
  198. int bootmeth_setup_fs(struct bootflow *bflow, struct blk_desc *desc)
  199. {
  200. int ret;
  201. if (desc) {
  202. ret = fs_set_blk_dev_with_part(desc, bflow->part);
  203. if (ret)
  204. return log_msg_ret("set", ret);
  205. } else if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && bflow->fs_type) {
  206. fs_set_type(bflow->fs_type);
  207. }
  208. return 0;
  209. }
  210. int bootmeth_try_file(struct bootflow *bflow, struct blk_desc *desc,
  211. const char *prefix, const char *fname)
  212. {
  213. char path[200];
  214. loff_t size;
  215. int ret, ret2;
  216. snprintf(path, sizeof(path), "%s%s", prefix ? prefix : "", fname);
  217. log_debug("trying: %s\n", path);
  218. free(bflow->fname);
  219. bflow->fname = strdup(path);
  220. if (!bflow->fname)
  221. return log_msg_ret("name", -ENOMEM);
  222. if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && bflow->fs_type)
  223. fs_set_type(bflow->fs_type);
  224. ret = fs_size(path, &size);
  225. log_debug(" %s - err=%d\n", path, ret);
  226. /* Sadly FS closes the file after fs_size() so we must redo this */
  227. ret2 = bootmeth_setup_fs(bflow, desc);
  228. if (ret2)
  229. return log_msg_ret("fs", ret2);
  230. if (ret)
  231. return log_msg_ret("size", ret);
  232. bflow->size = size;
  233. bflow->state = BOOTFLOWST_FILE;
  234. return 0;
  235. }
  236. int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align)
  237. {
  238. void *buf;
  239. uint size;
  240. int ret;
  241. size = bflow->size;
  242. log_debug(" - script file size %x\n", size);
  243. if (size > size_limit)
  244. return log_msg_ret("chk", -E2BIG);
  245. ret = fs_read_alloc(bflow->fname, bflow->size, align, &buf);
  246. if (ret)
  247. return log_msg_ret("all", ret);
  248. bflow->state = BOOTFLOWST_READY;
  249. bflow->buf = buf;
  250. return 0;
  251. }
  252. int bootmeth_alloc_other(struct bootflow *bflow, const char *fname,
  253. void **bufp, uint *sizep)
  254. {
  255. struct blk_desc *desc = NULL;
  256. char path[200];
  257. loff_t size;
  258. void *buf;
  259. int ret;
  260. snprintf(path, sizeof(path), "%s%s", bflow->subdir, fname);
  261. log_debug("trying: %s\n", path);
  262. if (bflow->blk)
  263. desc = dev_get_uclass_plat(bflow->blk);
  264. ret = bootmeth_setup_fs(bflow, desc);
  265. if (ret)
  266. return log_msg_ret("fs", ret);
  267. ret = fs_size(path, &size);
  268. log_debug(" %s - err=%d\n", path, ret);
  269. ret = bootmeth_setup_fs(bflow, desc);
  270. if (ret)
  271. return log_msg_ret("fs", ret);
  272. ret = fs_read_alloc(path, size, 0, &buf);
  273. if (ret)
  274. return log_msg_ret("all", ret);
  275. *bufp = buf;
  276. *sizep = size;
  277. return 0;
  278. }
  279. int bootmeth_common_read_file(struct udevice *dev, struct bootflow *bflow,
  280. const char *file_path, ulong addr, ulong *sizep)
  281. {
  282. struct blk_desc *desc = NULL;
  283. loff_t len_read;
  284. loff_t size;
  285. int ret;
  286. if (bflow->blk)
  287. desc = dev_get_uclass_plat(bflow->blk);
  288. ret = bootmeth_setup_fs(bflow, desc);
  289. if (ret)
  290. return log_msg_ret("fs", ret);
  291. ret = fs_size(file_path, &size);
  292. if (ret)
  293. return log_msg_ret("size", ret);
  294. if (size > *sizep)
  295. return log_msg_ret("spc", -ENOSPC);
  296. ret = bootmeth_setup_fs(bflow, desc);
  297. if (ret)
  298. return log_msg_ret("fs", ret);
  299. ret = fs_read(file_path, addr, 0, 0, &len_read);
  300. if (ret)
  301. return ret;
  302. *sizep = len_read;
  303. return 0;
  304. }
  305. #ifdef CONFIG_BOOTSTD_FULL
  306. /**
  307. * on_bootmeths() - Update the bootmeth order
  308. *
  309. * This will check for a valid list of bootmeths and only apply it if valid.
  310. */
  311. static int on_bootmeths(const char *name, const char *value, enum env_op op,
  312. int flags)
  313. {
  314. int ret;
  315. switch (op) {
  316. case env_op_create:
  317. case env_op_overwrite:
  318. ret = bootmeth_set_order(value);
  319. if (ret)
  320. return 1;
  321. return 0;
  322. case env_op_delete:
  323. bootmeth_set_order(NULL);
  324. fallthrough;
  325. default:
  326. return 0;
  327. }
  328. }
  329. U_BOOT_ENV_CALLBACK(bootmeths, on_bootmeths);
  330. #endif /* CONFIG_BOOTSTD_FULL */
  331. UCLASS_DRIVER(bootmeth) = {
  332. .id = UCLASS_BOOTMETH,
  333. .name = "bootmeth",
  334. .flags = DM_UC_FLAG_SEQ_ALIAS,
  335. .per_device_plat_auto = sizeof(struct bootmeth_uc_plat),
  336. };