510-block-add-uImage.FIT-subimage-block-driver.patch 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. From 6173a065cb395d4a9528c4e49810af127db68141 Mon Sep 17 00:00:00 2001
  2. From: Daniel Golle <[email protected]>
  3. Date: Wed, 16 Nov 2022 12:49:52 +0000
  4. Subject: [PATCH 1/2] block: add uImage.FIT subimage block driver
  5. Add a small block driver which exposes filesystem sub-images contained
  6. in U-Boot uImage.FIT images as block devices.
  7. The uImage.FIT image has to be stored directly on a block device or
  8. partition, MTD device or partition, or UBI volume.
  9. The driver is intended for systems using the U-Boot bootloader and
  10. uses the root device hint left by the bootloader (or the user) in
  11. the 'chosen' section of the device-tree.
  12. Example:
  13. /dts-v1/;
  14. / {
  15. chosen {
  16. rootdisk = <&mmc0_part3>;
  17. };
  18. };
  19. Signed-off-by: Daniel Golle <[email protected]>
  20. ---
  21. MAINTAINERS | 6 +
  22. drivers/block/Kconfig | 12 +
  23. drivers/block/Makefile | 2 +
  24. drivers/block/fitblk.c | 658 ++++++++++++++++++++++++++++++++++++
  25. drivers/block/open | 4 +
  26. include/uapi/linux/fitblk.h | 10 +
  27. 6 files changed, 692 insertions(+)
  28. create mode 100644 drivers/block/fitblk.c
  29. create mode 100644 drivers/block/open
  30. create mode 100644 include/uapi/linux/fitblk.h
  31. --- a/MAINTAINERS
  32. +++ b/MAINTAINERS
  33. @@ -22006,6 +22006,12 @@ F: Documentation/filesystems/ubifs-authe
  34. F: Documentation/filesystems/ubifs.rst
  35. F: fs/ubifs/
  36. +U-BOOT UIMAGE.FIT PARSER
  37. +M: Daniel Golle <[email protected]>
  38. +L: [email protected]
  39. +S: Maintained
  40. +F: drivers/block/fitblk.c
  41. +
  42. UBLK USERSPACE BLOCK DRIVER
  43. M: Ming Lei <[email protected]>
  44. L: [email protected]
  45. --- a/drivers/block/Kconfig
  46. +++ b/drivers/block/Kconfig
  47. @@ -354,6 +354,18 @@ config VIRTIO_BLK
  48. This is the virtual block driver for virtio. It can be used with
  49. QEMU based VMMs (like KVM or Xen). Say Y or M.
  50. +config UIMAGE_FIT_BLK
  51. + bool "uImage.FIT block driver"
  52. + help
  53. + This driver allows using filesystems contained in uImage.FIT images
  54. + by mapping them as block devices.
  55. +
  56. + It can currently not be built as a module due to libfdt symbols not
  57. + being exported.
  58. +
  59. + Say Y if you want to mount filesystems sub-images of a uImage.FIT
  60. + stored in a block device partition, mtdblock or ubiblock device.
  61. +
  62. config BLK_DEV_RBD
  63. tristate "Rados block device (RBD)"
  64. depends on INET && BLOCK
  65. --- a/drivers/block/Makefile
  66. +++ b/drivers/block/Makefile
  67. @@ -39,4 +39,6 @@ obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_b
  68. obj-$(CONFIG_BLK_DEV_UBLK) += ublk_drv.o
  69. +obj-$(CONFIG_UIMAGE_FIT_BLK) += fitblk.o
  70. +
  71. swim_mod-y := swim.o swim_asm.o
  72. --- /dev/null
  73. +++ b/drivers/block/fitblk.c
  74. @@ -0,0 +1,659 @@
  75. +// SPDX-License-Identifier: GPL-2.0-only
  76. +/*
  77. + * uImage.FIT virtual block device driver.
  78. + *
  79. + * Copyright (C) 2023 Daniel Golle
  80. + * Copyright (C) 2007 Nick Piggin
  81. + * Copyright (C) 2007 Novell Inc.
  82. + *
  83. + * Initially derived from drivers/block/brd.c which is in parts derived from
  84. + * drivers/block/rd.c, and drivers/block/loop.c, copyright of their respective
  85. + * owners.
  86. + *
  87. + * uImage.FIT headers extracted from Das U-Boot
  88. + * (C) Copyright 2008 Semihalf
  89. + * (C) Copyright 2000-2005
  90. + * Wolfgang Denk, DENX Software Engineering, [email protected].
  91. + */
  92. +
  93. +#include <linux/init.h>
  94. +#include <linux/initrd.h>
  95. +#include <linux/module.h>
  96. +#include <linux/moduleparam.h>
  97. +#include <linux/major.h>
  98. +#include <linux/blkdev.h>
  99. +#include <linux/blkpg.h>
  100. +#include <linux/blk-mq.h>
  101. +#include <linux/ctype.h>
  102. +#include <linux/hdreg.h>
  103. +#include <linux/list.h>
  104. +#include <linux/mutex.h>
  105. +#include <linux/of.h>
  106. +#include <linux/of_device.h>
  107. +#include <linux/of_fdt.h>
  108. +#include <linux/pagemap.h>
  109. +#include <linux/platform_device.h>
  110. +#include <linux/property.h>
  111. +#include <linux/refcount.h>
  112. +#include <linux/task_work.h>
  113. +#include <linux/types.h>
  114. +#include <linux/libfdt.h>
  115. +#include <linux/mtd/mtd.h>
  116. +#include <linux/root_dev.h>
  117. +#include <uapi/linux/fitblk.h>
  118. +
  119. +#define FIT_DEVICE_PREFIX "fit"
  120. +
  121. +/* maximum number of pages used for the uImage.FIT index structure */
  122. +#define FIT_MAX_PAGES 1024
  123. +
  124. +/* minimum free sectors to map as read-write "remainder" volume */
  125. +#define MIN_FREE_SECT 16
  126. +
  127. +/* maximum number of mapped loadables */
  128. +#define MAX_FIT_LOADABLES 16
  129. +
  130. +/* constants for uImage.FIT structrure traversal */
  131. +#define FIT_IMAGES_PATH "/images"
  132. +#define FIT_CONFS_PATH "/configurations"
  133. +
  134. +/* hash/signature/key node */
  135. +#define FIT_HASH_NODENAME "hash"
  136. +#define FIT_ALGO_PROP "algo"
  137. +#define FIT_VALUE_PROP "value"
  138. +#define FIT_IGNORE_PROP "uboot-ignore"
  139. +#define FIT_SIG_NODENAME "signature"
  140. +#define FIT_KEY_REQUIRED "required"
  141. +#define FIT_KEY_HINT "key-name-hint"
  142. +
  143. +/* cipher node */
  144. +#define FIT_CIPHER_NODENAME "cipher"
  145. +#define FIT_ALGO_PROP "algo"
  146. +
  147. +/* image node */
  148. +#define FIT_DATA_PROP "data"
  149. +#define FIT_DATA_POSITION_PROP "data-position"
  150. +#define FIT_DATA_OFFSET_PROP "data-offset"
  151. +#define FIT_DATA_SIZE_PROP "data-size"
  152. +#define FIT_TIMESTAMP_PROP "timestamp"
  153. +#define FIT_DESC_PROP "description"
  154. +#define FIT_ARCH_PROP "arch"
  155. +#define FIT_TYPE_PROP "type"
  156. +#define FIT_OS_PROP "os"
  157. +#define FIT_COMP_PROP "compression"
  158. +#define FIT_ENTRY_PROP "entry"
  159. +#define FIT_LOAD_PROP "load"
  160. +
  161. +/* configuration node */
  162. +#define FIT_KERNEL_PROP "kernel"
  163. +#define FIT_FILESYSTEM_PROP "filesystem"
  164. +#define FIT_RAMDISK_PROP "ramdisk"
  165. +#define FIT_FDT_PROP "fdt"
  166. +#define FIT_LOADABLE_PROP "loadables"
  167. +#define FIT_DEFAULT_PROP "default"
  168. +#define FIT_SETUP_PROP "setup"
  169. +#define FIT_FPGA_PROP "fpga"
  170. +#define FIT_FIRMWARE_PROP "firmware"
  171. +#define FIT_STANDALONE_PROP "standalone"
  172. +
  173. +/* fitblk driver data */
  174. +static const char *_fitblk_claim_ptr = "I belong to fitblk";
  175. +static const char *ubootver;
  176. +struct device_node *rootdisk;
  177. +static struct platform_device *pdev;
  178. +static LIST_HEAD(fitblk_devices);
  179. +static DEFINE_MUTEX(devices_mutex);
  180. +refcount_t num_devs;
  181. +
  182. +struct fitblk {
  183. + struct platform_device *pdev;
  184. + struct block_device *lower_bdev;
  185. + sector_t start_sect;
  186. + struct gendisk *disk;
  187. + struct work_struct remove_work;
  188. + struct list_head list;
  189. + bool dead;
  190. +};
  191. +
  192. +static int fitblk_open(struct gendisk *disk, fmode_t mode)
  193. +{
  194. + struct fitblk *fitblk = disk->private_data;
  195. +
  196. + if (fitblk->dead)
  197. + return -ENOENT;
  198. +
  199. + return 0;
  200. +}
  201. +
  202. +static void fitblk_release(struct gendisk *disk)
  203. +{
  204. + return;
  205. +}
  206. +
  207. +static void fitblk_submit_bio(struct bio *orig_bio)
  208. +{
  209. + struct bio *bio = orig_bio;
  210. + struct fitblk *fitblk = bio->bi_bdev->bd_disk->private_data;
  211. +
  212. + if (fitblk->dead)
  213. + return;
  214. +
  215. + /* mangle bio and re-submit */
  216. + while (bio) {
  217. + bio->bi_iter.bi_sector += fitblk->start_sect;
  218. + bio->bi_bdev = fitblk->lower_bdev;
  219. + bio = bio->bi_next;
  220. + }
  221. + submit_bio(orig_bio);
  222. +}
  223. +
  224. +static void fitblk_remove(struct fitblk *fitblk)
  225. +{
  226. + blk_mark_disk_dead(fitblk->disk);
  227. + mutex_lock(&devices_mutex);
  228. + fitblk->dead = true;
  229. + list_del(&fitblk->list);
  230. + mutex_unlock(&devices_mutex);
  231. +
  232. + schedule_work(&fitblk->remove_work);
  233. +}
  234. +
  235. +static int fitblk_ioctl(struct block_device *bdev, fmode_t mode,
  236. + unsigned int cmd, unsigned long arg)
  237. +{
  238. + struct fitblk *fitblk = bdev->bd_disk->private_data;
  239. +
  240. + if (!capable(CAP_SYS_ADMIN))
  241. + return -EACCES;
  242. +
  243. + if (fitblk->dead)
  244. + return -ENOENT;
  245. +
  246. + switch (cmd) {
  247. + case FITBLK_RELEASE:
  248. + fitblk_remove(fitblk);
  249. + break;
  250. + default:
  251. + return -EINVAL;
  252. + }
  253. +
  254. + return 0;
  255. +}
  256. +
  257. +static const struct block_device_operations fitblk_fops = {
  258. + .owner = THIS_MODULE,
  259. + .ioctl = fitblk_ioctl,
  260. + .open = fitblk_open,
  261. + .release = fitblk_release,
  262. + .submit_bio = fitblk_submit_bio,
  263. +};
  264. +
  265. +static void fitblk_purge(struct work_struct *work)
  266. +{
  267. + struct fitblk *fitblk = container_of(work, struct fitblk, remove_work);
  268. +
  269. + //del_gendisk(fitblk->disk); // causes crash, not doing it doesn't matter
  270. + refcount_dec(&num_devs);
  271. + platform_device_del(fitblk->pdev);
  272. + platform_device_put(fitblk->pdev);
  273. +
  274. + if (refcount_dec_if_one(&num_devs)) {
  275. + sysfs_remove_link(&pdev->dev.kobj, "lower_dev");
  276. + blkdev_put(fitblk->lower_bdev, &_fitblk_claim_ptr);
  277. + }
  278. +
  279. + kfree(fitblk);
  280. +}
  281. +
  282. +static int add_fit_subimage_device(struct block_device *lower_bdev,
  283. + unsigned int slot, sector_t start_sect,
  284. + sector_t nr_sect, bool readonly)
  285. +{
  286. + struct fitblk *fitblk;
  287. + struct gendisk *disk;
  288. + int err;
  289. +
  290. + mutex_lock(&devices_mutex);
  291. + if (!refcount_inc_not_zero(&num_devs))
  292. + return -EBADF;
  293. +
  294. + fitblk = kzalloc(sizeof(struct fitblk), GFP_KERNEL);
  295. + if (!fitblk) {
  296. + err = -ENOMEM;
  297. + goto out_unlock;
  298. + }
  299. +
  300. + fitblk->lower_bdev = lower_bdev;
  301. + fitblk->start_sect = start_sect;
  302. + INIT_WORK(&fitblk->remove_work, fitblk_purge);
  303. +
  304. + disk = blk_alloc_disk(NUMA_NO_NODE);
  305. + if (!disk) {
  306. + err = -ENOMEM;
  307. + goto out_free_fitblk;
  308. + }
  309. +
  310. + disk->first_minor = 0;
  311. + disk->flags = lower_bdev->bd_disk->flags | GENHD_FL_NO_PART;
  312. + disk->fops = &fitblk_fops;
  313. + disk->private_data = fitblk;
  314. + if (readonly) {
  315. + set_disk_ro(disk, 1);
  316. + snprintf(disk->disk_name, sizeof(disk->disk_name), FIT_DEVICE_PREFIX "%u", slot);
  317. + } else {
  318. + strcpy(disk->disk_name, FIT_DEVICE_PREFIX "rw");
  319. + }
  320. +
  321. + set_capacity(disk, nr_sect);
  322. +
  323. + disk->queue->queue_flags = lower_bdev->bd_disk->queue->queue_flags;
  324. + memcpy(&disk->queue->limits, &lower_bdev->bd_disk->queue->limits,
  325. + sizeof(struct queue_limits));
  326. +
  327. + fitblk->disk = disk;
  328. + fitblk->pdev = platform_device_alloc(disk->disk_name, PLATFORM_DEVID_NONE);
  329. + if (!fitblk->pdev) {
  330. + err = -ENOMEM;
  331. + goto out_cleanup_disk;
  332. + }
  333. +
  334. + fitblk->pdev->dev.parent = &pdev->dev;
  335. + err = platform_device_add(fitblk->pdev);
  336. + if (err)
  337. + goto out_put_pdev;
  338. +
  339. + err = device_add_disk(&fitblk->pdev->dev, disk, NULL);
  340. + if (err)
  341. + goto out_del_pdev;
  342. +
  343. + if (!ROOT_DEV)
  344. + ROOT_DEV = disk->part0->bd_dev;
  345. +
  346. + list_add_tail(&fitblk->list, &fitblk_devices);
  347. +
  348. + mutex_unlock(&devices_mutex);
  349. +
  350. + return 0;
  351. +
  352. +out_del_pdev:
  353. + platform_device_del(fitblk->pdev);
  354. +out_put_pdev:
  355. + platform_device_put(fitblk->pdev);
  356. +out_cleanup_disk:
  357. + put_disk(disk);
  358. +out_free_fitblk:
  359. + kfree(fitblk);
  360. +out_unlock:
  361. + refcount_dec(&num_devs);
  362. + mutex_unlock(&devices_mutex);
  363. + return err;
  364. +}
  365. +
  366. +static void fitblk_mark_dead(struct block_device *bdev, bool surprise)
  367. +{
  368. + struct list_head *n, *tmp;
  369. + struct fitblk *fitblk;
  370. +
  371. + mutex_lock(&devices_mutex);
  372. + list_for_each_safe(n, tmp, &fitblk_devices) {
  373. + fitblk = list_entry(n, struct fitblk, list);
  374. + if (fitblk->lower_bdev != bdev)
  375. + continue;
  376. +
  377. + fitblk->dead = true;
  378. + list_del(&fitblk->list);
  379. + /* removal needs to be deferred to avoid deadlock */
  380. + schedule_work(&fitblk->remove_work);
  381. + }
  382. + mutex_unlock(&devices_mutex);
  383. +}
  384. +
  385. +static const struct blk_holder_ops fitblk_hops = {
  386. + .mark_dead = fitblk_mark_dead,
  387. +};
  388. +
  389. +static int parse_fit_on_dev(struct device *dev)
  390. +{
  391. + struct block_device *bdev;
  392. + struct address_space *mapping;
  393. + struct folio *folio;
  394. + pgoff_t f_index = 0;
  395. + size_t bytes_left, bytes_to_copy;
  396. + void *pre_fit, *fit, *fit_c;
  397. + u64 dsize, dsectors, imgmaxsect = 0;
  398. + u32 size, image_pos, image_len;
  399. + const __be32 *image_offset_be, *image_len_be, *image_pos_be;
  400. + int ret = 0, node, images, config;
  401. + const char *image_name, *image_type, *image_description,
  402. + *config_default, *config_description, *config_loadables;
  403. + u32 image_name_len, image_type_len, image_description_len,
  404. + bootconf_len, config_default_len, config_description_len,
  405. + config_loadables_len;
  406. + sector_t start_sect, nr_sects;
  407. + struct device_node *np = NULL;
  408. + const char *bootconf_c;
  409. + const char *loadable;
  410. + char *bootconf = NULL, *bootconf_term;
  411. + bool found;
  412. + int loadables_rem_len, loadable_len;
  413. + u16 loadcnt;
  414. + unsigned int slot = 0;
  415. +
  416. + /* Exclusive open the block device to receive holder notifications */
  417. + bdev = blkdev_get_by_dev(dev->devt, BLK_OPEN_READ, &_fitblk_claim_ptr, &fitblk_hops);
  418. + if (!bdev)
  419. + return -ENODEV;
  420. +
  421. + if (IS_ERR(bdev))
  422. + return PTR_ERR(bdev);
  423. +
  424. + mapping = bdev->bd_inode->i_mapping;
  425. +
  426. + /* map first page */
  427. + folio = read_mapping_folio(mapping, f_index++, NULL);
  428. + if (IS_ERR(folio)) {
  429. + ret = PTR_ERR(folio);
  430. + goto out_blkdev;
  431. + }
  432. + pre_fit = folio_address(folio) + offset_in_folio(folio, 0);
  433. +
  434. + /* uImage.FIT is based on flattened device tree structure */
  435. + if (fdt_check_header(pre_fit)) {
  436. + ret = -EINVAL;
  437. + folio_put(folio);
  438. + goto out_blkdev;
  439. + }
  440. +
  441. + size = fdt_totalsize(pre_fit);
  442. +
  443. + if (size > PAGE_SIZE * FIT_MAX_PAGES) {
  444. + ret = -EOPNOTSUPP;
  445. + folio_put(folio);
  446. + goto out_blkdev;
  447. + }
  448. +
  449. + /* acquire disk size */
  450. + dsectors = bdev_nr_sectors(bdev);
  451. + dsize = dsectors << SECTOR_SHIFT;
  452. +
  453. + /* abort if FIT structure is larger than disk or partition size */
  454. + if (size >= dsize) {
  455. + ret = -EFBIG;
  456. + folio_put(folio);
  457. + goto out_blkdev;
  458. + }
  459. +
  460. + fit = kmalloc(size, GFP_KERNEL);
  461. + if (!fit) {
  462. + ret = -ENOMEM;
  463. + folio_put(folio);
  464. + goto out_blkdev;
  465. + }
  466. +
  467. + bytes_left = size;
  468. + fit_c = fit;
  469. + while (bytes_left > 0) {
  470. + bytes_to_copy = min_t(size_t, bytes_left,
  471. + folio_size(folio) - offset_in_folio(folio, 0));
  472. + memcpy(fit_c, pre_fit, bytes_to_copy);
  473. + fit_c += bytes_to_copy;
  474. + bytes_left -= bytes_to_copy;
  475. + if (bytes_left) {
  476. + folio_put(folio);
  477. + folio = read_mapping_folio(mapping, f_index++, NULL);
  478. + if (IS_ERR(folio)) {
  479. + ret = PTR_ERR(folio);
  480. + goto out_blkdev;
  481. + };
  482. + pre_fit = folio_address(folio) + offset_in_folio(folio, 0);
  483. + }
  484. + }
  485. + folio_put(folio);
  486. +
  487. + /* set boot config node name U-Boot may have added to the device tree */
  488. + np = of_find_node_by_path("/chosen");
  489. + if (np) {
  490. + bootconf_c = of_get_property(np, "u-boot,bootconf", &bootconf_len);
  491. + if (bootconf_c && bootconf_len)
  492. + bootconf = kmemdup_nul(bootconf_c, bootconf_len, GFP_KERNEL);
  493. + }
  494. +
  495. + if (bootconf) {
  496. + bootconf_term = strchr(bootconf, '#');
  497. + if (bootconf_term)
  498. + *bootconf_term = '\0';
  499. + }
  500. +
  501. + /* find configuration path in uImage.FIT */
  502. + config = fdt_path_offset(fit, FIT_CONFS_PATH);
  503. + if (config < 0) {
  504. + pr_err("FIT: Cannot find %s node: %d\n",
  505. + FIT_CONFS_PATH, config);
  506. + ret = -ENOENT;
  507. + goto out_bootconf;
  508. + }
  509. +
  510. + /* get default configuration node name */
  511. + config_default =
  512. + fdt_getprop(fit, config, FIT_DEFAULT_PROP, &config_default_len);
  513. +
  514. + /* make sure we got either default or selected boot config node name */
  515. + if (!config_default && !bootconf) {
  516. + pr_err("FIT: Cannot find default configuration\n");
  517. + ret = -ENOENT;
  518. + goto out_bootconf;
  519. + }
  520. +
  521. + /* find selected boot config node, fallback on default config node */
  522. + node = fdt_subnode_offset(fit, config, bootconf ?: config_default);
  523. + if (node < 0) {
  524. + pr_err("FIT: Cannot find %s node: %d\n",
  525. + bootconf ?: config_default, node);
  526. + ret = -ENOENT;
  527. + goto out_bootconf;
  528. + }
  529. +
  530. + pr_info("FIT: Detected U-Boot %s\n", ubootver);
  531. +
  532. + /* get selected configuration data */
  533. + config_description =
  534. + fdt_getprop(fit, node, FIT_DESC_PROP, &config_description_len);
  535. + config_loadables = fdt_getprop(fit, node, FIT_LOADABLE_PROP,
  536. + &config_loadables_len);
  537. +
  538. + pr_info("FIT: %s configuration: \"%.*s\"%s%.*s%s\n",
  539. + bootconf ? "Selected" : "Default",
  540. + bootconf ? bootconf_len : config_default_len,
  541. + bootconf ?: config_default,
  542. + config_description ? " (" : "",
  543. + config_description ? config_description_len : 0,
  544. + config_description ?: "",
  545. + config_description ? ")" : "");
  546. +
  547. + if (!config_loadables || !config_loadables_len) {
  548. + pr_err("FIT: No loadables configured in \"%s\"\n",
  549. + bootconf ?: config_default);
  550. + ret = -ENOENT;
  551. + goto out_bootconf;
  552. + }
  553. +
  554. + /* get images path in uImage.FIT */
  555. + images = fdt_path_offset(fit, FIT_IMAGES_PATH);
  556. + if (images < 0) {
  557. + pr_err("FIT: Cannot find %s node: %d\n", FIT_IMAGES_PATH, images);
  558. + ret = -EINVAL;
  559. + goto out_bootconf;
  560. + }
  561. +
  562. + /* iterate over images in uImage.FIT */
  563. + fdt_for_each_subnode(node, fit, images) {
  564. + image_name = fdt_get_name(fit, node, &image_name_len);
  565. + image_type = fdt_getprop(fit, node, FIT_TYPE_PROP, &image_type_len);
  566. + image_offset_be = fdt_getprop(fit, node, FIT_DATA_OFFSET_PROP, NULL);
  567. + image_pos_be = fdt_getprop(fit, node, FIT_DATA_POSITION_PROP, NULL);
  568. + image_len_be = fdt_getprop(fit, node, FIT_DATA_SIZE_PROP, NULL);
  569. +
  570. + if (!image_name || !image_type || !image_len_be ||
  571. + !image_name_len || !image_type_len)
  572. + continue;
  573. +
  574. + image_len = be32_to_cpu(*image_len_be);
  575. + if (!image_len)
  576. + continue;
  577. +
  578. + if (image_offset_be)
  579. + image_pos = be32_to_cpu(*image_offset_be) + size;
  580. + else if (image_pos_be)
  581. + image_pos = be32_to_cpu(*image_pos_be);
  582. + else
  583. + continue;
  584. +
  585. + image_description = fdt_getprop(fit, node, FIT_DESC_PROP,
  586. + &image_description_len);
  587. +
  588. + pr_info("FIT: %16s sub-image 0x%08x..0x%08x \"%.*s\"%s%.*s%s\n",
  589. + image_type, image_pos, image_pos + image_len - 1,
  590. + image_name_len, image_name, image_description ? " (" : "",
  591. + image_description ? image_description_len : 0,
  592. + image_description ?: "", image_description ? ") " : "");
  593. +
  594. + /* only 'filesystem' images should be mapped as partitions */
  595. + if (strncmp(image_type, FIT_FILESYSTEM_PROP, image_type_len))
  596. + continue;
  597. +
  598. + /* check if sub-image is part of configured loadables */
  599. + found = false;
  600. + loadable = config_loadables;
  601. + loadables_rem_len = config_loadables_len;
  602. + for (loadcnt = 0; loadables_rem_len > 1 &&
  603. + loadcnt < MAX_FIT_LOADABLES; ++loadcnt) {
  604. + loadable_len =
  605. + strnlen(loadable, loadables_rem_len - 1) + 1;
  606. + loadables_rem_len -= loadable_len;
  607. + if (!strncmp(image_name, loadable, loadable_len)) {
  608. + found = true;
  609. + break;
  610. + }
  611. + loadable += loadable_len;
  612. + }
  613. + if (!found)
  614. + continue;
  615. +
  616. + if (image_pos % (1 << PAGE_SHIFT)) {
  617. + dev_err(dev, "FIT: image %.*s start not aligned to page boundaries, skipping\n",
  618. + image_name_len, image_name);
  619. + continue;
  620. + }
  621. +
  622. + if (image_len % (1 << PAGE_SHIFT)) {
  623. + dev_err(dev, "FIT: sub-image %.*s end not aligned to page boundaries, skipping\n",
  624. + image_name_len, image_name);
  625. + continue;
  626. + }
  627. +
  628. + start_sect = image_pos >> SECTOR_SHIFT;
  629. + nr_sects = image_len >> SECTOR_SHIFT;
  630. + imgmaxsect = max_t(sector_t, imgmaxsect, start_sect + nr_sects);
  631. +
  632. + if (start_sect + nr_sects > dsectors) {
  633. + dev_err(dev, "FIT: sub-image %.*s disk access beyond EOD\n",
  634. + image_name_len, image_name);
  635. + continue;
  636. + }
  637. +
  638. + if (!slot) {
  639. + ret = sysfs_create_link_nowarn(&pdev->dev.kobj, bdev_kobj(bdev), "lower_dev");
  640. + if (ret && ret != -EEXIST)
  641. + goto out_bootconf;
  642. +
  643. + ret = 0;
  644. + }
  645. +
  646. + add_fit_subimage_device(bdev, slot++, start_sect, nr_sects, true);
  647. + }
  648. +
  649. + if (!found || !slot)
  650. + goto out_bootconf;
  651. +
  652. + dev_info(dev, "mapped %u uImage.FIT filesystem sub-image%s as /dev/fit%s%u%s\n",
  653. + slot, (slot > 1)?"s":"", (slot > 1)?"[0...":"", slot - 1,
  654. + (slot > 1)?"]":"");
  655. +
  656. + /* in case uImage.FIT is stored in a partition, map the remaining space */
  657. + if (!bdev->bd_read_only && bdev_is_partition(bdev) &&
  658. + (imgmaxsect + MIN_FREE_SECT) < dsectors) {
  659. + add_fit_subimage_device(bdev, slot++, imgmaxsect,
  660. + dsectors - imgmaxsect, false);
  661. + dev_info(dev, "mapped remaing space as /dev/fitrw\n");
  662. + }
  663. +
  664. +out_bootconf:
  665. + kfree(bootconf);
  666. + kfree(fit);
  667. +out_blkdev:
  668. + if (!found || ret)
  669. + blkdev_put(bdev, &_fitblk_claim_ptr);
  670. +
  671. + return ret;
  672. +}
  673. +
  674. +static int fitblk_match_of_node(struct device *dev, const void *np)
  675. +{
  676. + int ret;
  677. +
  678. + ret = device_match_of_node(dev, np);
  679. + if (ret)
  680. + return ret;
  681. +
  682. + /*
  683. + * To match ubiblock and mtdblock devices by their parent ubi
  684. + * or mtd device, also consider block device parent
  685. + */
  686. + if (!dev->parent)
  687. + return 0;
  688. +
  689. + return device_match_of_node(dev->parent, np);
  690. +}
  691. +
  692. +static int fitblk_probe(struct platform_device *pdev)
  693. +{
  694. + struct device *dev;
  695. +
  696. + dev = class_find_device(&block_class, NULL, rootdisk, fitblk_match_of_node);
  697. + if (!dev)
  698. + return -EPROBE_DEFER;
  699. +
  700. + return parse_fit_on_dev(dev);
  701. +}
  702. +
  703. +static struct platform_driver fitblk_driver = {
  704. + .probe = fitblk_probe,
  705. + .driver = {
  706. + .name = "fitblk",
  707. + .owner = THIS_MODULE,
  708. + },
  709. +};
  710. +
  711. +static int __init fitblk_init(void)
  712. +{
  713. + /* detect U-Boot firmware */
  714. + ubootver = of_get_property(of_chosen, "u-boot,version", NULL);
  715. + if (!ubootver)
  716. + return 0;
  717. +
  718. + /* parse 'rootdisk' property phandle */
  719. + rootdisk = of_parse_phandle(of_chosen, "rootdisk", 0);
  720. + if (!rootdisk)
  721. + return 0;
  722. +
  723. + if (platform_driver_register(&fitblk_driver))
  724. + return -ENODEV;
  725. +
  726. + refcount_set(&num_devs, 1);
  727. + pdev = platform_device_register_simple("fitblk", -1, NULL, 0);
  728. + if (IS_ERR(pdev))
  729. + return PTR_ERR(pdev);
  730. +
  731. + return 0;
  732. +}
  733. +device_initcall(fitblk_init);
  734. --- /dev/null
  735. +++ b/include/uapi/linux/fitblk.h
  736. @@ -0,0 +1,10 @@
  737. +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
  738. +#ifndef _UAPI_LINUX_FITBLK_H
  739. +#define _UAPI_LINUX_FITBLK_H
  740. +
  741. +/*
  742. + * IOCTL commands --- we will commandeer 0x46 ('F')
  743. + */
  744. +#define FITBLK_RELEASE 0x4600
  745. +
  746. +#endif /* _UAPI_LINUX_FITBLK_H */