blkmap.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2023 Addiva Elektronik
  4. * Author: Tobias Waldekranz <tobias@waldekranz.com>
  5. */
  6. #include <common.h>
  7. #include <blk.h>
  8. #include <blkmap.h>
  9. #include <dm.h>
  10. #include <malloc.h>
  11. #include <mapmem.h>
  12. #include <part.h>
  13. #include <dm/device-internal.h>
  14. #include <dm/lists.h>
  15. #include <dm/root.h>
  16. struct blkmap;
  17. /**
  18. * struct blkmap_slice - Region mapped to a blkmap
  19. *
  20. * Common data for a region mapped to a blkmap, specialized by each
  21. * map type.
  22. *
  23. * @node: List node used to associate this slice with a blkmap
  24. * @blknr: Start block number of the mapping
  25. * @blkcnt: Number of blocks covered by this mapping
  26. */
  27. struct blkmap_slice {
  28. struct list_head node;
  29. lbaint_t blknr;
  30. lbaint_t blkcnt;
  31. /**
  32. * @read: - Read from slice
  33. *
  34. * @read.bm: Blkmap to which this slice belongs
  35. * @read.bms: This slice
  36. * @read.blknr: Start block number to read from
  37. * @read.blkcnt: Number of blocks to read
  38. * @read.buffer: Buffer to store read data to
  39. */
  40. ulong (*read)(struct blkmap *bm, struct blkmap_slice *bms,
  41. lbaint_t blknr, lbaint_t blkcnt, void *buffer);
  42. /**
  43. * @write: - Write to slice
  44. *
  45. * @write.bm: Blkmap to which this slice belongs
  46. * @write.bms: This slice
  47. * @write.blknr: Start block number to write to
  48. * @write.blkcnt: Number of blocks to write
  49. * @write.buffer: Data to be written
  50. */
  51. ulong (*write)(struct blkmap *bm, struct blkmap_slice *bms,
  52. lbaint_t blknr, lbaint_t blkcnt, const void *buffer);
  53. /**
  54. * @destroy: - Tear down slice
  55. *
  56. * @read.bm: Blkmap to which this slice belongs
  57. * @read.bms: This slice
  58. */
  59. void (*destroy)(struct blkmap *bm, struct blkmap_slice *bms);
  60. };
  61. /**
  62. * struct blkmap - Block map
  63. *
  64. * Data associated with a blkmap.
  65. *
  66. * @label: Human readable name of this blkmap
  67. * @blk: Underlying block device
  68. * @slices: List of slices associated with this blkmap
  69. */
  70. struct blkmap {
  71. char *label;
  72. struct udevice *blk;
  73. struct list_head slices;
  74. };
  75. static bool blkmap_slice_contains(struct blkmap_slice *bms, lbaint_t blknr)
  76. {
  77. return (blknr >= bms->blknr) && (blknr < (bms->blknr + bms->blkcnt));
  78. }
  79. static bool blkmap_slice_available(struct blkmap *bm, struct blkmap_slice *new)
  80. {
  81. struct blkmap_slice *bms;
  82. lbaint_t first, last;
  83. first = new->blknr;
  84. last = new->blknr + new->blkcnt - 1;
  85. list_for_each_entry(bms, &bm->slices, node) {
  86. if (blkmap_slice_contains(bms, first) ||
  87. blkmap_slice_contains(bms, last) ||
  88. blkmap_slice_contains(new, bms->blknr) ||
  89. blkmap_slice_contains(new, bms->blknr + bms->blkcnt - 1))
  90. return false;
  91. }
  92. return true;
  93. }
  94. static int blkmap_slice_add(struct blkmap *bm, struct blkmap_slice *new)
  95. {
  96. struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
  97. struct list_head *insert = &bm->slices;
  98. struct blkmap_slice *bms;
  99. if (!blkmap_slice_available(bm, new))
  100. return -EBUSY;
  101. list_for_each_entry(bms, &bm->slices, node) {
  102. if (bms->blknr < new->blknr)
  103. continue;
  104. insert = &bms->node;
  105. break;
  106. }
  107. list_add_tail(&new->node, insert);
  108. /* Disk might have grown, update the size */
  109. bms = list_last_entry(&bm->slices, struct blkmap_slice, node);
  110. bd->lba = bms->blknr + bms->blkcnt;
  111. return 0;
  112. }
  113. /**
  114. * struct blkmap_linear - Linear mapping to other block device
  115. *
  116. * @slice: Common map data
  117. * @blk: Target block device of this mapping
  118. * @blknr: Start block number of the target device
  119. */
  120. struct blkmap_linear {
  121. struct blkmap_slice slice;
  122. struct udevice *blk;
  123. lbaint_t blknr;
  124. };
  125. static ulong blkmap_linear_read(struct blkmap *bm, struct blkmap_slice *bms,
  126. lbaint_t blknr, lbaint_t blkcnt, void *buffer)
  127. {
  128. struct blkmap_linear *bml = container_of(bms, struct blkmap_linear, slice);
  129. return blk_read(bml->blk, bml->blknr + blknr, blkcnt, buffer);
  130. }
  131. static ulong blkmap_linear_write(struct blkmap *bm, struct blkmap_slice *bms,
  132. lbaint_t blknr, lbaint_t blkcnt,
  133. const void *buffer)
  134. {
  135. struct blkmap_linear *bml = container_of(bms, struct blkmap_linear, slice);
  136. return blk_write(bml->blk, bml->blknr + blknr, blkcnt, buffer);
  137. }
  138. int blkmap_map_linear(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
  139. struct udevice *lblk, lbaint_t lblknr)
  140. {
  141. struct blkmap *bm = dev_get_plat(dev);
  142. struct blkmap_linear *linear;
  143. struct blk_desc *bd, *lbd;
  144. int err;
  145. bd = dev_get_uclass_plat(bm->blk);
  146. lbd = dev_get_uclass_plat(lblk);
  147. if (lbd->blksz != bd->blksz)
  148. /* We could support block size translation, but we
  149. * don't yet.
  150. */
  151. return -EINVAL;
  152. linear = malloc(sizeof(*linear));
  153. if (!linear)
  154. return -ENOMEM;
  155. *linear = (struct blkmap_linear) {
  156. .slice = {
  157. .blknr = blknr,
  158. .blkcnt = blkcnt,
  159. .read = blkmap_linear_read,
  160. .write = blkmap_linear_write,
  161. },
  162. .blk = lblk,
  163. .blknr = lblknr,
  164. };
  165. err = blkmap_slice_add(bm, &linear->slice);
  166. if (err)
  167. free(linear);
  168. return err;
  169. }
  170. /**
  171. * struct blkmap_mem - Memory mapping
  172. *
  173. * @slice: Common map data
  174. * @addr: Target memory region of this mapping
  175. * @remapped: True if @addr is backed by a physical to virtual memory
  176. * mapping that must be torn down at the end of this mapping's
  177. * lifetime.
  178. */
  179. struct blkmap_mem {
  180. struct blkmap_slice slice;
  181. void *addr;
  182. bool remapped;
  183. };
  184. static ulong blkmap_mem_read(struct blkmap *bm, struct blkmap_slice *bms,
  185. lbaint_t blknr, lbaint_t blkcnt, void *buffer)
  186. {
  187. struct blkmap_mem *bmm = container_of(bms, struct blkmap_mem, slice);
  188. struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
  189. char *src;
  190. src = bmm->addr + (blknr << bd->log2blksz);
  191. memcpy(buffer, src, blkcnt << bd->log2blksz);
  192. return blkcnt;
  193. }
  194. static ulong blkmap_mem_write(struct blkmap *bm, struct blkmap_slice *bms,
  195. lbaint_t blknr, lbaint_t blkcnt,
  196. const void *buffer)
  197. {
  198. struct blkmap_mem *bmm = container_of(bms, struct blkmap_mem, slice);
  199. struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
  200. char *dst;
  201. dst = bmm->addr + (blknr << bd->log2blksz);
  202. memcpy(dst, buffer, blkcnt << bd->log2blksz);
  203. return blkcnt;
  204. }
  205. static void blkmap_mem_destroy(struct blkmap *bm, struct blkmap_slice *bms)
  206. {
  207. struct blkmap_mem *bmm = container_of(bms, struct blkmap_mem, slice);
  208. if (bmm->remapped)
  209. unmap_sysmem(bmm->addr);
  210. }
  211. int __blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
  212. void *addr, bool remapped)
  213. {
  214. struct blkmap *bm = dev_get_plat(dev);
  215. struct blkmap_mem *bmm;
  216. int err;
  217. bmm = malloc(sizeof(*bmm));
  218. if (!bmm)
  219. return -ENOMEM;
  220. *bmm = (struct blkmap_mem) {
  221. .slice = {
  222. .blknr = blknr,
  223. .blkcnt = blkcnt,
  224. .read = blkmap_mem_read,
  225. .write = blkmap_mem_write,
  226. .destroy = blkmap_mem_destroy,
  227. },
  228. .addr = addr,
  229. .remapped = remapped,
  230. };
  231. err = blkmap_slice_add(bm, &bmm->slice);
  232. if (err)
  233. free(bmm);
  234. return err;
  235. }
  236. int blkmap_map_mem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
  237. void *addr)
  238. {
  239. return __blkmap_map_mem(dev, blknr, blkcnt, addr, false);
  240. }
  241. int blkmap_map_pmem(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
  242. phys_addr_t paddr)
  243. {
  244. struct blkmap *bm = dev_get_plat(dev);
  245. struct blk_desc *bd = dev_get_uclass_plat(bm->blk);
  246. void *addr;
  247. int err;
  248. addr = map_sysmem(paddr, blkcnt << bd->log2blksz);
  249. if (!addr)
  250. return -ENOMEM;
  251. err = __blkmap_map_mem(dev, blknr, blkcnt, addr, true);
  252. if (err)
  253. unmap_sysmem(addr);
  254. return err;
  255. }
  256. static ulong blkmap_blk_read_slice(struct blkmap *bm, struct blkmap_slice *bms,
  257. lbaint_t blknr, lbaint_t blkcnt,
  258. void *buffer)
  259. {
  260. lbaint_t nr, cnt;
  261. nr = blknr - bms->blknr;
  262. cnt = (blkcnt < bms->blkcnt) ? blkcnt : bms->blkcnt;
  263. return bms->read(bm, bms, nr, cnt, buffer);
  264. }
  265. static ulong blkmap_blk_read(struct udevice *dev, lbaint_t blknr,
  266. lbaint_t blkcnt, void *buffer)
  267. {
  268. struct blk_desc *bd = dev_get_uclass_plat(dev);
  269. struct blkmap *bm = dev_get_plat(dev->parent);
  270. struct blkmap_slice *bms;
  271. lbaint_t cnt, total = 0;
  272. list_for_each_entry(bms, &bm->slices, node) {
  273. if (!blkmap_slice_contains(bms, blknr))
  274. continue;
  275. cnt = blkmap_blk_read_slice(bm, bms, blknr, blkcnt, buffer);
  276. blknr += cnt;
  277. blkcnt -= cnt;
  278. buffer += cnt << bd->log2blksz;
  279. total += cnt;
  280. }
  281. return total;
  282. }
  283. static ulong blkmap_blk_write_slice(struct blkmap *bm, struct blkmap_slice *bms,
  284. lbaint_t blknr, lbaint_t blkcnt,
  285. const void *buffer)
  286. {
  287. lbaint_t nr, cnt;
  288. nr = blknr - bms->blknr;
  289. cnt = (blkcnt < bms->blkcnt) ? blkcnt : bms->blkcnt;
  290. return bms->write(bm, bms, nr, cnt, buffer);
  291. }
  292. static ulong blkmap_blk_write(struct udevice *dev, lbaint_t blknr,
  293. lbaint_t blkcnt, const void *buffer)
  294. {
  295. struct blk_desc *bd = dev_get_uclass_plat(dev);
  296. struct blkmap *bm = dev_get_plat(dev->parent);
  297. struct blkmap_slice *bms;
  298. lbaint_t cnt, total = 0;
  299. list_for_each_entry(bms, &bm->slices, node) {
  300. if (!blkmap_slice_contains(bms, blknr))
  301. continue;
  302. cnt = blkmap_blk_write_slice(bm, bms, blknr, blkcnt, buffer);
  303. blknr += cnt;
  304. blkcnt -= cnt;
  305. buffer += cnt << bd->log2blksz;
  306. total += cnt;
  307. }
  308. return total;
  309. }
  310. static const struct blk_ops blkmap_blk_ops = {
  311. .read = blkmap_blk_read,
  312. .write = blkmap_blk_write,
  313. };
  314. U_BOOT_DRIVER(blkmap_blk) = {
  315. .name = "blkmap_blk",
  316. .id = UCLASS_BLK,
  317. .ops = &blkmap_blk_ops,
  318. };
  319. int blkmap_dev_bind(struct udevice *dev)
  320. {
  321. struct blkmap *bm = dev_get_plat(dev);
  322. struct blk_desc *bd;
  323. int err;
  324. err = blk_create_devicef(dev, "blkmap_blk", "blk", UCLASS_BLKMAP,
  325. dev_seq(dev), 512, 0, &bm->blk);
  326. if (err)
  327. return log_msg_ret("blk", err);
  328. INIT_LIST_HEAD(&bm->slices);
  329. bd = dev_get_uclass_plat(bm->blk);
  330. snprintf(bd->vendor, BLK_VEN_SIZE, "U-Boot");
  331. snprintf(bd->product, BLK_PRD_SIZE, "blkmap");
  332. snprintf(bd->revision, BLK_REV_SIZE, "1.0");
  333. /* EFI core isn't keen on zero-sized disks, so we lie. This is
  334. * updated with the correct size once the user adds a
  335. * mapping.
  336. */
  337. bd->lba = 1;
  338. return 0;
  339. }
  340. int blkmap_dev_unbind(struct udevice *dev)
  341. {
  342. struct blkmap *bm = dev_get_plat(dev);
  343. struct blkmap_slice *bms, *tmp;
  344. int err;
  345. list_for_each_entry_safe(bms, tmp, &bm->slices, node) {
  346. list_del(&bms->node);
  347. free(bms);
  348. }
  349. err = device_remove(bm->blk, DM_REMOVE_NORMAL);
  350. if (err)
  351. return err;
  352. return device_unbind(bm->blk);
  353. }
  354. U_BOOT_DRIVER(blkmap_root) = {
  355. .name = "blkmap_dev",
  356. .id = UCLASS_BLKMAP,
  357. .bind = blkmap_dev_bind,
  358. .unbind = blkmap_dev_unbind,
  359. .plat_auto = sizeof(struct blkmap),
  360. };
  361. struct udevice *blkmap_from_label(const char *label)
  362. {
  363. struct udevice *dev;
  364. struct uclass *uc;
  365. struct blkmap *bm;
  366. uclass_id_foreach_dev(UCLASS_BLKMAP, dev, uc) {
  367. bm = dev_get_plat(dev);
  368. if (bm->label && !strcmp(label, bm->label))
  369. return dev;
  370. }
  371. return NULL;
  372. }
  373. int blkmap_create(const char *label, struct udevice **devp)
  374. {
  375. char *hname, *hlabel;
  376. struct udevice *dev;
  377. struct blkmap *bm;
  378. size_t namelen;
  379. int err;
  380. dev = blkmap_from_label(label);
  381. if (dev) {
  382. err = -EBUSY;
  383. goto err;
  384. }
  385. hlabel = strdup(label);
  386. if (!hlabel) {
  387. err = -ENOMEM;
  388. goto err;
  389. }
  390. namelen = strlen("blkmap-") + strlen(label) + 1;
  391. hname = malloc(namelen);
  392. if (!hname) {
  393. err = -ENOMEM;
  394. goto err_free_hlabel;
  395. }
  396. strlcpy(hname, "blkmap-", namelen);
  397. strlcat(hname, label, namelen);
  398. err = device_bind_driver(dm_root(), "blkmap_dev", hname, &dev);
  399. if (err)
  400. goto err_free_hname;
  401. device_set_name_alloced(dev);
  402. bm = dev_get_plat(dev);
  403. bm->label = hlabel;
  404. if (devp)
  405. *devp = dev;
  406. return 0;
  407. err_free_hname:
  408. free(hname);
  409. err_free_hlabel:
  410. free(hlabel);
  411. err:
  412. return err;
  413. }
  414. int blkmap_destroy(struct udevice *dev)
  415. {
  416. int err;
  417. err = device_remove(dev, DM_REMOVE_NORMAL);
  418. if (err)
  419. return err;
  420. return device_unbind(dev);
  421. }
  422. UCLASS_DRIVER(blkmap) = {
  423. .id = UCLASS_BLKMAP,
  424. .name = "blkmap",
  425. };