mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* fastboot sparse support
@ 2018-01-11  7:50 Sascha Hauer
  2018-01-11  7:50 ` [PATCH 1/7] fs: implement ftruncate Sascha Hauer
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Sascha Hauer @ 2018-01-11  7:50 UTC (permalink / raw)
  To: Barebox List

This series adds support for Sparse images to the fastboot code.
Sparse images are necessary to flash images that do not fit into memory.

This requires more changes than I'd like to have, but unfortunately
we have to change the ubiformat code to flash parts of images instead
of only whole images. This change also makes the newly introduced
'u' flag (u for UBI) in the partition description for fastboot necessary.

Anyway, in the end it works as expected and memory size is no longer
a limit for fastboot.

Sascha

----------------------------------------------------------------
Sascha Hauer (7):
      fs: implement ftruncate
      ubiformat: Add ubiformat write function
      Documentation: USB gadget: Add section for partition description
      filetype: Add fastboot sparse format detection
      Add support for fastboot sparse images
      file_list: Add ubi flag
      usb: gadget: fastboot: Add sparse image support

 Documentation/user/usb.rst      |  49 ++++++--
 common/file-list.c              |   3 +
 common/filetype.c               |   5 +
 common/ubiformat.c              |  61 ++++++++++
 drivers/usb/gadget/Kconfig      |   1 +
 drivers/usb/gadget/f_fastboot.c | 235 +++++++++++++++++++++++++++++++++----
 fs/fs.c                         |  22 ++++
 include/file-list.h             |   1 +
 include/filetype.h              |   1 +
 include/image-sparse.h          |  67 +++++++++++
 include/ubiformat.h             |   3 +
 include/unistd.h                |   1 +
 lib/Kconfig                     |   3 +
 lib/Makefile                    |   1 +
 lib/image-sparse.c              | 249 ++++++++++++++++++++++++++++++++++++++++
 15 files changed, 669 insertions(+), 33 deletions(-)
 create mode 100644 include/image-sparse.h
 create mode 100644 lib/image-sparse.c

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/7] fs: implement ftruncate
  2018-01-11  7:50 fastboot sparse support Sascha Hauer
@ 2018-01-11  7:50 ` Sascha Hauer
  2018-01-11  7:50 ` [PATCH 2/7] ubiformat: Add ubiformat write function Sascha Hauer
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2018-01-11  7:50 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/fs.c          | 22 ++++++++++++++++++++++
 include/unistd.h |  1 +
 2 files changed, 23 insertions(+)

diff --git a/fs/fs.c b/fs/fs.c
index f61ee091b5..051af8d19f 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -742,6 +742,28 @@ int creat(const char *pathname, mode_t mode)
 }
 EXPORT_SYMBOL(creat);
 
+int ftruncate(int fd, loff_t length)
+{
+	struct fs_driver_d *fsdrv;
+	FILE *f;
+	int ret;
+
+	if (check_fd(fd))
+		return -errno;
+
+	f = &files[fd];
+
+	fsdrv = f->fsdev->driver;
+
+	ret = fsdrv->truncate(&f->fsdev->dev, f, length);
+	if (ret)
+		return ret;
+
+	f->size = length;
+
+	return 0;
+}
+
 int ioctl(int fd, int request, void *buf)
 {
 	struct fs_driver_d *fsdrv;
diff --git a/include/unistd.h b/include/unistd.h
index 31f430a5b6..f392e6dd6c 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -20,5 +20,6 @@ int symlink(const char *pathname, const char *newpath);
 int readlink(const char *path, char *buf, size_t bufsiz);
 int chdir(const char *pathname);
 const char *getcwd(void);
+int ftruncate(int fd, loff_t length);
 
 #endif /* __UNISTD_H */
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 2/7] ubiformat: Add ubiformat write function
  2018-01-11  7:50 fastboot sparse support Sascha Hauer
  2018-01-11  7:50 ` [PATCH 1/7] fs: implement ftruncate Sascha Hauer
@ 2018-01-11  7:50 ` Sascha Hauer
  2018-01-11  7:50 ` [PATCH 3/7] Documentation: USB gadget: Add section for partition description Sascha Hauer
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2018-01-11  7:50 UTC (permalink / raw)
  To: Barebox List

The ubiformat C API expects an image file as argument. With upcoming
Android fastboot sparse image support we can no longer provide a
complete image anymore. With this patch we can write an image in
multiple chunks after we've formatted a MTD device with ubiformat.

ubiformat_write will skip the EC header in both the MTD device we
write to and also the image we read from, so we can flash an image
on a MTD device containing EC headers already.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/ubiformat.c  | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/ubiformat.h |  3 +++
 2 files changed, 64 insertions(+)

diff --git a/common/ubiformat.c b/common/ubiformat.c
index aaa1f5d6bc..4c5f1f5794 100644
--- a/common/ubiformat.c
+++ b/common/ubiformat.c
@@ -679,3 +679,64 @@ out_close:
 	return err;
 }
 
+int ubiformat_write(struct mtd_info *mtd, const void *buf, size_t count,
+		    loff_t offset)
+{
+	int writesize = mtd->writesize >> mtd->subpage_sft;
+	size_t retlen;
+	int ret;
+
+	if (offset & (mtd->writesize - 1))
+		return -EINVAL;
+
+	if (count & (mtd->writesize - 1))
+		return -EINVAL;
+
+	while (count) {
+		size_t now;
+
+		now = ALIGN(offset, mtd->erasesize) - offset;
+		if (now > count)
+			now = count;
+
+		if (!now) {
+			const struct ubi_ec_hdr *ec = buf;
+			const struct ubi_vid_hdr *vid;
+
+			if (be32_to_cpu(ec->magic) != UBI_EC_HDR_MAGIC) {
+				pr_err("bad UBI magic %#08x, should be %#08x",
+					be32_to_cpu(ec->magic), UBI_EC_HDR_MAGIC);
+				return -EINVAL;
+			}
+
+			/* skip ec header */
+			offset += writesize;
+			buf += writesize;
+			count -= writesize;
+
+			if (!count)
+				break;
+
+			vid = buf;
+			if (be32_to_cpu(vid->magic) != UBI_VID_HDR_MAGIC) {
+				pr_err("bad UBI magic %#08x, should be %#08x",
+				       be32_to_cpu(vid->magic), UBI_VID_HDR_MAGIC);
+				return -EINVAL;
+			}
+
+			continue;
+		}
+
+		ret = mtd_write(mtd, offset, now, &retlen, buf);
+		if (ret < 0)
+			return ret;
+		if (retlen != now)
+			return -EIO;
+
+		buf += now;
+		count -= now;
+		offset += now;
+	}
+
+	return 0;
+}
diff --git a/include/ubiformat.h b/include/ubiformat.h
index b195fd8392..8305a853c7 100644
--- a/include/ubiformat.h
+++ b/include/ubiformat.h
@@ -20,4 +20,7 @@ struct ubiformat_args {
 
 int ubiformat(struct mtd_info *mtd, struct ubiformat_args *args);
 
+int ubiformat_write(struct mtd_info *mtd, const void *buf, size_t count,
+		    loff_t offset);
+
 #endif /* __UBIFORMAT_H */
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 3/7] Documentation: USB gadget: Add section for partition description
  2018-01-11  7:50 fastboot sparse support Sascha Hauer
  2018-01-11  7:50 ` [PATCH 1/7] fs: implement ftruncate Sascha Hauer
  2018-01-11  7:50 ` [PATCH 2/7] ubiformat: Add ubiformat write function Sascha Hauer
@ 2018-01-11  7:50 ` Sascha Hauer
  2018-01-11  7:50 ` [PATCH 4/7] filetype: Add fastboot sparse format detection Sascha Hauer
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2018-01-11  7:50 UTC (permalink / raw)
  To: Barebox List

Partition descriptions are used with both fastboot and DFU, so add
a separate section describing them and remove it from the DFU section.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 Documentation/user/usb.rst | 48 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 38 insertions(+), 10 deletions(-)

diff --git a/Documentation/user/usb.rst b/Documentation/user/usb.rst
index ec219cfbe4..3844e7941a 100644
--- a/Documentation/user/usb.rst
+++ b/Documentation/user/usb.rst
@@ -35,6 +35,42 @@ command, they show up as ``/dev/diskx`` and can be used like any other device.
 USB device support
 ------------------
 
+barebox supports several different USB gadget drivers:
+
+- Device Firmware Upgrade (DFU)
+- Android Fastboot
+- serial gadget
+
+The recommended way to use USB gadget is with the :ref:`command_usbgadget` command.
+While there are individual commands for :ref:`command_dfu` and :ref:`command_usbserial`,
+the :ref:`command_usbgadget` commands supports registering composite gadgets.
+
+Partition description
+^^^^^^^^^^^^^^^^^^^^^
+
+The USB gadget commands for Android Fastboot and DFU take a partition description
+which describes which barebox partitions are exported via USB. The partition
+description is referred to as ``<desc>`` in the command help texts. It has
+the general form ``partition(name)flags,partition(name)flags,...``.
+
+The **partition** field is the partition as accessible in barebox. This can be a
+path in ``/dev/``, but could also be a regular file.
+
+The **name** field is the name under which the partition shall be exported. This
+is the name under which the partition can be found with the host tool.
+
+Several **flags** are supported, each denoted by a single character:
+
+* ``s`` Safe mode. The file is downloaded completely before it is written (DFU specific)
+* ``r`` Readback. The partition is allowed to be read back (DFU specific)
+* ``c`` The file shall be created if it doesn't exist. Needed when a regular file is exported.
+
+Example:
+
+.. code-block:: sh
+
+  /dev/nand0.barebox.bb(barebox)sr,/kernel(kernel)rc
+
 DFU
 ^^^
 
@@ -43,16 +79,8 @@ Implementers Forum. It provides a vendor-independent way to update the firmware
 devices. The current specification is version 1.1 and can be downloaded here:
 http://www.usb.org/developers/devclass_docs/DFU_1.1.pdf
 
-On the barebox side, the update is handled with the :ref:`command_dfu` command.
-It is passed a list of partitions to provide to the host. The partition list
-has the form ``<file>(<name>)<flags>``.  ``file`` is the path to the device or
-regular file which shall be updated. ``name`` is the name under which the partition
-shall be provided to the host. For the possible ``flags`` see
-:ref:`command_dfu`. A typical ``dfu`` command could look like this:
-
-.. code-block:: sh
-
-  dfu "/dev/nand0.barebox.bb(barebox)sr,/dev/nand0.kernel.bb(kernel)r,/dev/nand0.root.bb(root)r"
+On the barebox side, the update is handled with the :ref:`command_usbgadget` or the
+:ref:`command_dfu` command.
 
 On the host side, the tool `dfu-util <http://dfu-util.gnumonks.org/>`_ can be used
 to update the partitions. It is available for most distributions and typically
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 4/7] filetype: Add fastboot sparse format detection
  2018-01-11  7:50 fastboot sparse support Sascha Hauer
                   ` (2 preceding siblings ...)
  2018-01-11  7:50 ` [PATCH 3/7] Documentation: USB gadget: Add section for partition description Sascha Hauer
@ 2018-01-11  7:50 ` Sascha Hauer
  2018-01-11  7:50 ` [PATCH 5/7] Add support for fastboot sparse images Sascha Hauer
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2018-01-11  7:50 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/filetype.c  | 5 +++++
 include/filetype.h | 1 +
 2 files changed, 6 insertions(+)

diff --git a/common/filetype.c b/common/filetype.c
index 323da026af..f9c034ff2a 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -25,6 +25,7 @@
 #include <errno.h>
 #include <envfs.h>
 #include <disks.h>
+#include <image-sparse.h>
 
 struct filetype_str {
 	const char *name;	/* human readable filetype */
@@ -64,6 +65,7 @@ static const struct filetype_str filetype_str[] = {
 	[filetype_mxs_bootstream] = { "Freescale MXS bootstream", "mxsbs" },
 	[filetype_socfpga_xload] = { "SoCFPGA prebootloader image", "socfpga-xload" },
 	[filetype_kwbimage_v1] = { "MVEBU kwbimage (v1)", "kwb" },
+	[filetype_android_sparse] = { "Android sparse image", "sparse" },
 };
 
 const char *file_type_to_string(enum filetype f)
@@ -301,6 +303,9 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
 	    (buf8[0x1e] == 0 || buf8[0x1e] == 1))
 		return filetype_kwbimage_v1;
 
+	if (is_sparse_image(_buf))
+		return filetype_android_sparse;
+
 	if (bufsize < 64)
 		return filetype_unknown;
 
diff --git a/include/filetype.h b/include/filetype.h
index c84905d782..b98dcb5014 100644
--- a/include/filetype.h
+++ b/include/filetype.h
@@ -39,6 +39,7 @@ enum filetype {
 	filetype_mxs_bootstream,
 	filetype_socfpga_xload,
 	filetype_kwbimage_v1,
+	filetype_android_sparse,
 	filetype_max,
 };
 
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 5/7] Add support for fastboot sparse images
  2018-01-11  7:50 fastboot sparse support Sascha Hauer
                   ` (3 preceding siblings ...)
  2018-01-11  7:50 ` [PATCH 4/7] filetype: Add fastboot sparse format detection Sascha Hauer
@ 2018-01-11  7:50 ` Sascha Hauer
  2018-01-11  7:50 ` [PATCH 6/7] file_list: Add ubi flag Sascha Hauer
  2018-01-11  7:50 ` [PATCH 7/7] usb: gadget: fastboot: Add sparse image support Sascha Hauer
  6 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2018-01-11  7:50 UTC (permalink / raw)
  To: Barebox List

This adds support for reading Android fastboot sparse images. This
code is based on the corresponding U-Boot code, but has been heavily
modified to provide a read-like API which better fits into barebox.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 include/image-sparse.h |  67 +++++++++++++
 lib/Kconfig            |   3 +
 lib/Makefile           |   1 +
 lib/image-sparse.c     | 249 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 320 insertions(+)
 create mode 100644 include/image-sparse.h
 create mode 100644 lib/image-sparse.c

diff --git a/include/image-sparse.h b/include/image-sparse.h
new file mode 100644
index 0000000000..29242f4fd5
--- /dev/null
+++ b/include/image-sparse.h
@@ -0,0 +1,67 @@
+/*
+ * This is from the Android Project,
+ * Repository: https://android.googlesource.com/platform/system/core
+ * File: libsparse/sparse_format.h
+ * Commit: 28fa5bc347390480fe190294c6c385b6a9f0d68b
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _IMAGE_SPARSE_H
+#define _IMAGE_SPARSE_H
+
+struct sparse_header {
+  __le32	magic;		/* 0xed26ff3a */
+  __le16	major_version;	/* (0x1) - reject images with higher major versions */
+  __le16	minor_version;	/* (0x0) - allow images with higer minor versions */
+  __le16	file_hdr_sz;	/* 28 bytes for first revision of the file format */
+  __le16	chunk_hdr_sz;	/* 12 bytes for first revision of the file format */
+  __le32	blk_sz;		/* block size in bytes, must be a multiple of 4 (4096) */
+  __le32	total_blks;	/* total blocks in the non-sparse output image */
+  __le32	total_chunks;	/* total chunks in the sparse input image */
+  __le32	image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
+				/* as 0. Standard 802.3 polynomial, use a Public Domain */
+				/* table implementation */
+};
+
+#define SPARSE_HEADER_MAGIC	0xed26ff3a
+
+#define CHUNK_TYPE_RAW		0xCAC1
+#define CHUNK_TYPE_FILL		0xCAC2
+#define CHUNK_TYPE_DONT_CARE	0xCAC3
+#define CHUNK_TYPE_CRC32    0xCAC4
+
+struct chunk_header {
+  __le16	chunk_type;	/* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
+  __le16	reserved1;
+  __le32	chunk_sz;	/* in blocks in output image */
+  __le32	total_sz;	/* in bytes of chunk input file including chunk header and data */
+};
+
+/* Following a Raw or Fill or CRC32 chunk is data.
+ *  For a Raw chunk, it's the data in chunk_sz * blk_sz.
+ *  For a Fill chunk, it's 4 bytes of the fill data.
+ *  For a CRC32 chunk, it's 4 bytes of CRC32
+ */
+
+static inline int is_sparse_image(const void *buf)
+{
+	const struct sparse_header *s = buf;
+
+	if ((le32_to_cpu(s->magic) == SPARSE_HEADER_MAGIC) &&
+	    (le16_to_cpu(s->major_version) == 1))
+		return 1;
+
+	return 0;
+}
+
+struct sparse_image_ctx;
+
+struct sparse_image_ctx *sparse_image_open(const char *path);
+int sparse_image_read(struct sparse_image_ctx *si, void *buf,
+		      loff_t *pos, size_t len, int *retlen);
+void sparse_image_close(struct sparse_image_ctx *si);
+loff_t sparse_image_size(struct sparse_image_ctx *si);
+
+#endif /* _IMAGE_SPARSE_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 9562b1b8c2..637b3f1003 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -79,6 +79,9 @@ config LIBSCAN
 config LIBUBIGEN
 	bool
 
+config IMAGE_SPARSE
+	bool
+
 config STMP_DEVICE
 	bool
 
diff --git a/lib/Makefile b/lib/Makefile
index 1be1742499..0d5ac6586c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o
 obj-y			+= glob.o
 obj-y			+= notifier.o
 obj-y			+= random.o
+obj-$(CONFIG_IMAGE_SPARSE) += image-sparse.o
 obj-y			+= lzo/
 obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/
 obj-y			+= show_progress.o
diff --git a/lib/image-sparse.c b/lib/image-sparse.c
new file mode 100644
index 0000000000..7137d15fd0
--- /dev/null
+++ b/lib/image-sparse.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
+ * Portions Copyright 2014 Broadcom Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of The Linux Foundation nor
+ *       the names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * NOTE:
+ *   Although it is very similar, this license text is not identical
+ *   to the "BSD-3-Clause", therefore, DO NOT MODIFY THIS LICENSE TEXT!
+ */
+#define pr_fmt(fmt)  "image-sparse: " fmt
+
+#include <config.h>
+#include <common.h>
+#include <image-sparse.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <fs.h>
+#include <libfile.h>
+#include <linux/sizes.h>
+
+#include <linux/math64.h>
+
+#ifndef CONFIG_FASTBOOT_FLASH_FILLBUF_SIZE
+#define CONFIG_FASTBOOT_FLASH_FILLBUF_SIZE (1024 * 512)
+#endif
+
+struct sparse_image_ctx {
+	int fd;
+	struct sparse_header sparse;
+	int processed_chunks;
+	struct chunk_header chunk;
+	loff_t pos;
+	size_t remaining;
+	uint32_t fill_val;
+};
+
+int sparse_seek(struct sparse_image_ctx *si)
+{
+	unsigned int chunk_data_sz, payload;
+	loff_t offs;
+	int ret;
+
+again:
+	if (si->processed_chunks == si->sparse.total_chunks)
+		return 0;
+
+	/* Read and skip over chunk header */
+	ret = read_full(si->fd, &si->chunk,
+			sizeof(struct chunk_header));
+	if (ret < 0)
+		return ret;
+	if (ret < sizeof(struct chunk_header))
+		return -EINVAL;
+
+	pr_debug("=== Chunk Header ===\n");
+	pr_debug("chunk_type: 0x%x\n", si->chunk.chunk_type);
+	pr_debug("chunk_data_sz: 0x%x\n", si->chunk.chunk_sz);
+	pr_debug("total_size: 0x%x\n", si->chunk.total_sz);
+
+	if (si->sparse.chunk_hdr_sz > sizeof(struct chunk_header)) {
+		/*
+		 * Skip the remaining bytes in a header that is longer
+		 * than we expected.
+		 */
+		offs = lseek(si->fd, si->sparse.chunk_hdr_sz -
+			 sizeof(struct chunk_header), SEEK_CUR);
+		if (offs == -1)
+			return -errno;
+	}
+
+	chunk_data_sz = si->sparse.blk_sz * si->chunk.chunk_sz;
+	payload = si->chunk.total_sz - si->sparse.chunk_hdr_sz;
+
+	si->processed_chunks++;
+
+	switch (si->chunk.chunk_type) {
+	case CHUNK_TYPE_RAW:
+		if (payload != chunk_data_sz)
+			return -EINVAL;
+
+		si->remaining = payload;
+
+		break;
+
+	case CHUNK_TYPE_FILL:
+		if (payload != sizeof(uint32_t))
+			return -EINVAL;
+
+		ret = read_full(si->fd, &si->fill_val, sizeof(uint32_t));
+		if (ret < 0)
+			return ret;
+		if (ret < sizeof(uint32_t))
+			return -EINVAL;
+
+		si->remaining = chunk_data_sz;
+
+		break;
+
+	case CHUNK_TYPE_DONT_CARE:
+		si->pos += chunk_data_sz;
+		goto again;
+
+	case CHUNK_TYPE_CRC32:
+		if (payload != sizeof(uint32_t))
+			return -EINVAL;
+
+		offs = lseek(si->fd, chunk_data_sz, SEEK_CUR);
+		if (offs == -1)
+			return -EINVAL;
+		goto again;
+
+	default:
+		pr_err("Unknown chunk type 0x%04x",
+				si->chunk.chunk_type);
+		return -EINVAL;
+	}
+
+	return 1;
+}
+
+loff_t sparse_image_size(struct sparse_image_ctx *si)
+{
+	return (loff_t)si->sparse.blk_sz * si->sparse.total_blks;
+}
+
+struct sparse_image_ctx *sparse_image_open(const char *path)
+{
+	struct sparse_image_ctx *si;
+	loff_t offs;
+	int ret;
+
+	si = xzalloc(sizeof(*si));
+
+	si->fd = open(path, O_RDONLY);
+	if (si->fd < 0) {
+		ret = -errno;
+		goto out;
+	}
+
+	/* Read and skip over sparse image header */
+	read(si->fd, &si->sparse, sizeof(struct sparse_header));
+
+	if (si->sparse.file_hdr_sz > sizeof(struct sparse_header)) {
+		/*
+		 * Skip the remaining bytes in a header that is longer than
+		 * we expected.
+		 */
+		offs = lseek(si->fd, si->sparse.file_hdr_sz, SEEK_SET);
+		if (offs == -1) {
+			ret = -errno;
+			goto out;
+		}
+	}
+
+	ret = sparse_seek(si);
+	if (ret < 0)
+		goto out;
+
+	return si;
+out:
+	free(si);
+
+	return ERR_PTR(ret);
+}
+
+int sparse_image_read(struct sparse_image_ctx *si, void *buf, loff_t *pos,
+		      size_t len, int *retlen)
+{
+	size_t now;
+	int ret, i;
+
+	if (si->remaining == 0) {
+		ret = sparse_seek(si);
+		if (ret < 0)
+			return ret;
+		if (ret == 0) {
+			*retlen = 0;
+			return 0;
+		}
+	}
+
+	*pos = si->pos;
+
+	now = min(si->remaining, len);
+
+	switch (si->chunk.chunk_type) {
+	case CHUNK_TYPE_RAW:
+		ret = read_full(si->fd, buf, now);
+		if (ret < 0)
+			return ret;
+		if (ret < now)
+			return -EINVAL;
+
+		break;
+
+	case CHUNK_TYPE_FILL:
+		if (now & 3)
+			return -EINVAL;
+
+		for (i = 0; i < now / sizeof(uint32_t); i++) {
+			uint32_t *buf32 = buf;
+
+			buf32[i] = si->fill_val;
+		}
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	si->pos += now;
+	si->remaining -= now;
+
+	*retlen = now;
+
+	return 0;
+}
+
+void sparse_image_close(struct sparse_image_ctx *si)
+{
+	close(si->fd);
+	free(si);
+}
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 6/7] file_list: Add ubi flag
  2018-01-11  7:50 fastboot sparse support Sascha Hauer
                   ` (4 preceding siblings ...)
  2018-01-11  7:50 ` [PATCH 5/7] Add support for fastboot sparse images Sascha Hauer
@ 2018-01-11  7:50 ` Sascha Hauer
  2018-01-11  7:50 ` [PATCH 7/7] usb: gadget: fastboot: Add sparse image support Sascha Hauer
  6 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2018-01-11  7:50 UTC (permalink / raw)
  To: Barebox List

This flag is added to better support flashing UBI image with Android
sparse images. Android fastboot splits images which are bigger than the
free memory into multiple images which are then transferred in multiple
fastboot sessions. In a session which is not the first one we can no
longer detect if an image is a UBI image or not, so we need a flag to
make this explicit.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/file-list.c  | 3 +++
 include/file-list.h | 1 +
 2 files changed, 4 insertions(+)

diff --git a/common/file-list.c b/common/file-list.c
index 8d61b76cbb..eb469cf9be 100644
--- a/common/file-list.c
+++ b/common/file-list.c
@@ -92,6 +92,9 @@ static int file_list_parse_one(struct file_list *files, const char *partstr, con
 			case 'c':
 				flags |= FILE_LIST_FLAG_CREATE;
 				break;
+			case 'u':
+				flags |= FILE_LIST_FLAG_UBI;
+				break;
 			default:
 				pr_err("Unknown flag '%c'\n", *partstr);
 				return -EINVAL;
diff --git a/include/file-list.h b/include/file-list.h
index 1e02539d4d..404d8d64bb 100644
--- a/include/file-list.h
+++ b/include/file-list.h
@@ -4,6 +4,7 @@
 #define FILE_LIST_FLAG_SAFE	(1 << 0)
 #define FILE_LIST_FLAG_READBACK	(1 << 1)
 #define FILE_LIST_FLAG_CREATE	(1 << 2)
+#define FILE_LIST_FLAG_UBI	(1 << 3)
 
 struct file_list_entry {
 	char *name;
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 7/7] usb: gadget: fastboot: Add sparse image support
  2018-01-11  7:50 fastboot sparse support Sascha Hauer
                   ` (5 preceding siblings ...)
  2018-01-11  7:50 ` [PATCH 6/7] file_list: Add ubi flag Sascha Hauer
@ 2018-01-11  7:50 ` Sascha Hauer
  2018-01-12  8:03   ` [PATCH] " Sascha Hauer
  6 siblings, 1 reply; 9+ messages in thread
From: Sascha Hauer @ 2018-01-11  7:50 UTC (permalink / raw)
  To: Barebox List

Sparse images are needed for fastboot to flash images that do not
fit into memory.

Android fastboot is kind of a dumb protocol. It first sends you a
big image and afterwards it tells you where to put this image. This
of course limits fastboot to files smaller than the available memory.
To bypass this issue fastboot has so called Sparse image support. This
is a new image format that can contain holes in the data so a big image
can be written in multiple steps with holes in other areas each step.

Implementing this for UBI images is kind of tricky since ubiformat
normally expects to get a single image. Preparations to ubiformat
a device in multiple parts have been done in previous patches.
It is however, only for the first part possible to detect if it is
a UBI image. The other parts are just binary data and we cannot
know if we have to pass this data raw to the flash or use ubiformat.
For this reason this patch makes the 'u' flag in the partition
description mandatory for proper UBI image flashing on MTD devices.

fastboot passes a max_download_size variable to the host. This
variable contains the image size fastboot can take in one go.
We have to choose a good compromise here. On one hand we do not
want to risk that we actually do not have enough memory to hold the
transferred image, on the other hand we want images like bootloaders
not as sparse images, but in one go instead to make atomic exchange
of the bootloader possible. Right now we have chosen 8MiB which
should be big enough for all bootloaders. The value is configurable
via global.usbgadget.fastboot_max_download_size.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 Documentation/user/usb.rst      |   1 +
 drivers/usb/gadget/Kconfig      |   1 +
 drivers/usb/gadget/f_fastboot.c | 235 ++++++++++++++++++++++++++++++++++++----
 3 files changed, 214 insertions(+), 23 deletions(-)

diff --git a/Documentation/user/usb.rst b/Documentation/user/usb.rst
index 3844e7941a..8396f3897c 100644
--- a/Documentation/user/usb.rst
+++ b/Documentation/user/usb.rst
@@ -64,6 +64,7 @@ Several **flags** are supported, each denoted by a single character:
 * ``s`` Safe mode. The file is downloaded completely before it is written (DFU specific)
 * ``r`` Readback. The partition is allowed to be read back (DFU specific)
 * ``c`` The file shall be created if it doesn't exist. Needed when a regular file is exported.
+* ``u`` The partition is a MTD device and shall be flashed with a UBI image.
 
 Example:
 
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 64347f0d18..b612d39a8e 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -57,6 +57,7 @@ config USB_GADGET_FASTBOOT
 	bool
 	select BANNER
 	select FILE_LIST
+	select IMAGE_SPARSE
 	prompt "Android Fastboot support"
 
 endif
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 85c64c05c8..4df87b9335 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -32,11 +32,14 @@
 #include <ubiformat.h>
 #include <stdlib.h>
 #include <file-list.h>
+#include <magicvar.h>
+#include <linux/sizes.h>
 #include <progress.h>
 #include <environment.h>
 #include <globalvar.h>
 #include <restart.h>
 #include <console_countdown.h>
+#include <image-sparse.h>
 #include <usb/ch9.h>
 #include <usb/gadget.h>
 #include <usb/fastboot.h>
@@ -45,6 +48,7 @@
 #include <linux/compiler.h>
 #include <linux/stat.h>
 #include <linux/mtd/mtd-abi.h>
+#include <linux/mtd/mtd.h>
 
 #define FASTBOOT_VERSION		"0.4"
 
@@ -56,6 +60,8 @@
 
 #define EP_BUFFER_SIZE			4096
 
+static unsigned int fastboot_max_download_size = SZ_8M;
+
 struct fb_variable {
 	char *name;
 	char *value;
@@ -316,6 +322,8 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
 	fb_setvar(var, "0.4");
 	var = fb_addvar(f_fb, "bootloader-version");
 	fb_setvar(var, release_string);
+	var = fb_addvar(f_fb, "max-download-size");
+	fb_setvar(var, "%u", fastboot_max_download_size);
 
 	if (IS_ENABLED(CONFIG_BAREBOX_UPDATE) && opts->export_bbu)
 		bbu_handlers_iterate(fastboot_add_bbu_variables, f_fb);
@@ -526,7 +534,7 @@ static int fastboot_tx_write(struct f_fastboot *f_fb, const char *buffer, unsign
 	return 0;
 }
 
-static int fastboot_tx_print(struct f_fastboot *f_fb, const char *fmt, ...)
+int fastboot_tx_print(struct f_fastboot *f_fb, const char *fmt, ...)
 {
 	char buf[64];
 	va_list ap;
@@ -687,6 +695,179 @@ static void __maybe_unused cb_boot(struct usb_ep *ep, struct usb_request *req,
 	fastboot_tx_print(f_fb, "OKAY");
 }
 
+static struct mtd_info *get_mtd(struct f_fastboot *f_fb, const char *filename)
+{
+	int fd, ret;
+	struct mtd_info_user meminfo;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return ERR_PTR(-errno);
+
+	ret = ioctl(fd, MEMGETINFO, &meminfo);
+
+	close(fd);
+
+	if (ret)
+		return ERR_PTR(ret);
+
+	return meminfo.mtd;
+}
+
+static int do_ubiformat(struct f_fastboot *f_fb, struct mtd_info *mtd,
+			const char *file)
+{
+	struct ubiformat_args args = {
+		.yes = 1,
+		.image = file,
+	};
+
+	if (!file)
+		args.novtbl = 1;
+
+	if (!IS_ENABLED(CONFIG_UBIFORMAT)) {
+		fastboot_tx_print(f_fb, "FAILubiformat is not available");
+		return -ENODEV;
+	}
+
+	return ubiformat(mtd, &args);
+}
+
+
+static int check_ubi(struct f_fastboot *f_fb, struct file_list_entry *fentry,
+		     enum filetype filetype)
+{
+	struct mtd_info *mtd;
+
+	mtd = get_mtd(f_fb, fentry->filename);
+
+	/*
+	 * Issue a warning when we are about to write a UBI image to a MTD device
+	 * and the FILE_LIST_FLAG_UBI is not given as this means we loose all
+	 * erase counters.
+	 */
+	if (!IS_ERR(mtd) && filetype == filetype_ubi &&
+	    !(fentry->flags & FILE_LIST_FLAG_UBI)) {
+		    fastboot_tx_print(f_fb, "INFOwriting UBI image to MTD device, "
+					    "add the 'u' ");
+		    fastboot_tx_print(f_fb, "INFOflag to the partition description");
+	}
+
+	if (filetype == filetype_ubi) {
+		fastboot_tx_print(f_fb, "INFOThis is an UBI image...");
+		return 0;
+	} else {
+		fastboot_tx_print(f_fb, "FAILThis is no UBI image but %s",
+			file_type_to_string(filetype));
+		return -EINVAL;
+	}
+}
+
+static int fastboot_handle_sparse(struct f_fastboot *f_fb,
+				  struct file_list_entry *fentry)
+{
+	struct sparse_image_ctx *sparse;
+	void *buf = NULL;
+	int ret, fd;
+	unsigned int flags = O_RDWR;
+	int bufsiz = SZ_128K;
+	struct stat s;
+	struct mtd_info *mtd = NULL;
+
+	ret = stat(fentry->filename, &s);
+	if (ret) {
+		if (fentry->flags & FILE_LIST_FLAG_CREATE)
+			flags |= O_CREAT;
+		else
+			return ret;
+	}
+
+	fd = open(fentry->filename, flags);
+	if (fd < 0)
+		return -errno;
+
+	ret = fstat(fd, &s);
+	if (ret)
+		goto out_close_fd;
+
+	sparse = sparse_image_open(FASTBOOT_TMPFILE);
+	if (IS_ERR(sparse)) {
+		pr_err("Cannot open sparse image\n");
+		ret = PTR_ERR(sparse);
+		goto out_close_fd;
+	}
+
+	if (S_ISREG(s.st_mode)) {
+		ret = ftruncate(fd, sparse_image_size(sparse));
+		if (ret)
+			goto out;
+	}
+
+	buf = malloc(bufsiz);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (fentry->flags & FILE_LIST_FLAG_UBI) {
+		mtd = get_mtd(f_fb, fentry->filename);
+		if (IS_ERR(mtd)) {
+			ret = PTR_ERR(mtd);
+			goto out;
+		}
+	}
+
+	while (1) {
+		int retlen;
+		loff_t pos;
+
+		ret = sparse_image_read(sparse, buf, &pos, bufsiz, &retlen);
+		if (ret)
+			goto out;
+		if (!retlen)
+			break;
+
+		if (pos == 0) {
+			ret = check_ubi(f_fb, fentry, file_detect_type(buf, retlen));
+			if (ret)
+				goto out;
+		}
+
+		if (fentry->flags & FILE_LIST_FLAG_UBI) {
+			if (pos == 0) {
+
+				ret = do_ubiformat(f_fb, mtd, NULL);
+				if (ret)
+					goto out;
+			}
+
+			ret = ubiformat_write(mtd, buf, retlen, pos);
+			if (ret)
+				goto out;
+		} else {
+			pos = lseek(fd, pos, SEEK_SET);
+			if (pos == -1) {
+				ret = -errno;
+				goto out;
+			}
+
+			ret = write_full(fd, buf, retlen);
+			if (ret < 0)
+				goto out;
+		}
+	}
+
+	ret = 0;
+
+out:
+	free(buf);
+	sparse_image_close(sparse);
+out_close_fd:
+	close(fd);
+
+	return ret;
+}
+
 static void cb_flash(struct usb_ep *ep, struct usb_request *req, const char *cmd)
 {
 	struct f_fastboot *f_fb = req->context;
@@ -706,33 +887,27 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req, const char *cmd
 
 	filename = fentry->filename;
 
-	if (filetype == filetype_ubi) {
-		int fd;
-		struct mtd_info_user meminfo;
-		struct ubiformat_args args = {
-			.yes = 1,
-			.image = FASTBOOT_TMPFILE,
-		};
-
-		fd = open(filename, O_RDONLY);
-		if (fd < 0)
-			goto copy;
+	if (filetype == filetype_android_sparse) {
+		ret = fastboot_handle_sparse(f_fb, fentry);
+		if (ret) {
+			fastboot_tx_print(f_fb, "FAILwriting sparse image: %s",
+					  strerror(-ret));
+			return;
+		}
 
-		ret = ioctl(fd, MEMGETINFO, &meminfo);
-		close(fd);
-		/* Not a MTD device, ubiformat is not a valid operation */
-		if (ret)
-			goto copy;
+		goto out;
+	}
 
-		fastboot_tx_print(f_fb, "INFOThis is an UBI image...");
+	ret = check_ubi(f_fb, fentry, filetype);
+	if (ret < 0)
+		return;
 
-		if (!IS_ENABLED(CONFIG_UBIFORMAT)) {
-			fastboot_tx_print(f_fb, "FAILubiformat is not available");
-			return;
-		}
+	if (ret) {
+		struct mtd_info *mtd;
 
-		ret = ubiformat(meminfo.mtd, &args);
+		mtd = get_mtd(f_fb, fentry->filename);
 
+		ret = do_ubiformat(f_fb, mtd, FASTBOOT_TMPFILE);
 		if (ret) {
 			fastboot_tx_print(f_fb, "FAILwrite partition: %s", strerror(-ret));
 			return;
@@ -973,3 +1148,17 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
 	memset(req->buf, 0, EP_BUFFER_SIZE);
 	usb_ep_queue(ep, req);
 }
+
+static int fastboot_globalvars_init(void)
+{
+	globalvar_add_simple_int("usbgadget.fastboot_max_download_size",
+				 &fastboot_max_download_size, "%u");
+
+	return 0;
+}
+
+device_initcall(fastboot_globalvars_init);
+
+BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_max_download_size,
+		       global.usbgadget.fastboot_max_download_size,
+		       "Fastboot maximum download size");
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH] usb: gadget: fastboot: Add sparse image support
  2018-01-11  7:50 ` [PATCH 7/7] usb: gadget: fastboot: Add sparse image support Sascha Hauer
@ 2018-01-12  8:03   ` Sascha Hauer
  0 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2018-01-12  8:03 UTC (permalink / raw)
  To: Barebox List

Sparse images are needed for fastboot to flash images that do not
fit into memory.

Android fastboot is kind of a dumb protocol. It first sends you a
big image and afterwards it tells you where to put this image. This
of course limits fastboot to files smaller than the available memory.
To bypass this issue fastboot has so called Sparse image support. This
is a new image format that can contain holes in the data so a big image
can be written in multiple steps with holes in other areas each step.

Implementing this for UBI images is kind of tricky since ubiformat
normally expects to get a single image. Preparations to ubiformat
a device in multiple parts have been done in previous patches.
It is however, only for the first part possible to detect if it is
a UBI image. The other parts are just binary data and we cannot
know if we have to pass this data raw to the flash or use ubiformat.
For this reason this patch makes the 'u' flag in the partition
description mandatory for proper UBI image flashing on MTD devices.

fastboot passes a max_download_size variable to the host. This
variable contains the image size fastboot can take in one go.
We have to choose a good compromise here. On one hand we do not
want to risk that we actually do not have enough memory to hold the
transferred image, on the other hand we want images like bootloaders
not as sparse images, but in one go instead to make atomic exchange
of the bootloader possible. Right now we have chosen 8MiB which
should be big enough for all bootloaders. The value is configurable
via global.usbgadget.fastboot_max_download_size.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 Documentation/user/usb.rst      |   1 +
 drivers/usb/gadget/Kconfig      |   1 +
 drivers/usb/gadget/f_fastboot.c | 243 ++++++++++++++++++++++++++++++++++++----
 3 files changed, 222 insertions(+), 23 deletions(-)

diff --git a/Documentation/user/usb.rst b/Documentation/user/usb.rst
index 3844e7941a..8396f3897c 100644
--- a/Documentation/user/usb.rst
+++ b/Documentation/user/usb.rst
@@ -64,6 +64,7 @@ Several **flags** are supported, each denoted by a single character:
 * ``s`` Safe mode. The file is downloaded completely before it is written (DFU specific)
 * ``r`` Readback. The partition is allowed to be read back (DFU specific)
 * ``c`` The file shall be created if it doesn't exist. Needed when a regular file is exported.
+* ``u`` The partition is a MTD device and shall be flashed with a UBI image.
 
 Example:
 
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 64347f0d18..b612d39a8e 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -57,6 +57,7 @@ config USB_GADGET_FASTBOOT
 	bool
 	select BANNER
 	select FILE_LIST
+	select IMAGE_SPARSE
 	prompt "Android Fastboot support"
 
 endif
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 85c64c05c8..4f4f3fff26 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -32,11 +32,14 @@
 #include <ubiformat.h>
 #include <stdlib.h>
 #include <file-list.h>
+#include <magicvar.h>
+#include <linux/sizes.h>
 #include <progress.h>
 #include <environment.h>
 #include <globalvar.h>
 #include <restart.h>
 #include <console_countdown.h>
+#include <image-sparse.h>
 #include <usb/ch9.h>
 #include <usb/gadget.h>
 #include <usb/fastboot.h>
@@ -45,6 +48,7 @@
 #include <linux/compiler.h>
 #include <linux/stat.h>
 #include <linux/mtd/mtd-abi.h>
+#include <linux/mtd/mtd.h>
 
 #define FASTBOOT_VERSION		"0.4"
 
@@ -56,6 +60,8 @@
 
 #define EP_BUFFER_SIZE			4096
 
+static unsigned int fastboot_max_download_size = SZ_8M;
+
 struct fb_variable {
 	char *name;
 	char *value;
@@ -316,6 +322,8 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f)
 	fb_setvar(var, "0.4");
 	var = fb_addvar(f_fb, "bootloader-version");
 	fb_setvar(var, release_string);
+	var = fb_addvar(f_fb, "max-download-size");
+	fb_setvar(var, "%u", fastboot_max_download_size);
 
 	if (IS_ENABLED(CONFIG_BAREBOX_UPDATE) && opts->export_bbu)
 		bbu_handlers_iterate(fastboot_add_bbu_variables, f_fb);
@@ -526,7 +534,7 @@ static int fastboot_tx_write(struct f_fastboot *f_fb, const char *buffer, unsign
 	return 0;
 }
 
-static int fastboot_tx_print(struct f_fastboot *f_fb, const char *fmt, ...)
+int fastboot_tx_print(struct f_fastboot *f_fb, const char *fmt, ...)
 {
 	char buf[64];
 	va_list ap;
@@ -687,6 +695,187 @@ static void __maybe_unused cb_boot(struct usb_ep *ep, struct usb_request *req,
 	fastboot_tx_print(f_fb, "OKAY");
 }
 
+static struct mtd_info *get_mtd(struct f_fastboot *f_fb, const char *filename)
+{
+	int fd, ret;
+	struct mtd_info_user meminfo;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return ERR_PTR(-errno);
+
+	ret = ioctl(fd, MEMGETINFO, &meminfo);
+
+	close(fd);
+
+	if (ret)
+		return ERR_PTR(ret);
+
+	return meminfo.mtd;
+}
+
+static int do_ubiformat(struct f_fastboot *f_fb, struct mtd_info *mtd,
+			const char *file)
+{
+	struct ubiformat_args args = {
+		.yes = 1,
+		.image = file,
+	};
+
+	if (!file)
+		args.novtbl = 1;
+
+	if (!IS_ENABLED(CONFIG_UBIFORMAT)) {
+		fastboot_tx_print(f_fb, "FAILubiformat is not available");
+		return -ENODEV;
+	}
+
+	return ubiformat(mtd, &args);
+}
+
+
+static int check_ubi(struct f_fastboot *f_fb, struct file_list_entry *fentry,
+		     enum filetype filetype)
+{
+	struct mtd_info *mtd;
+
+	mtd = get_mtd(f_fb, fentry->filename);
+
+	/*
+	 * Issue a warning when we are about to write a UBI image to a MTD device
+	 * and the FILE_LIST_FLAG_UBI is not given as this means we loose all
+	 * erase counters.
+	 */
+	if (!IS_ERR(mtd) && filetype == filetype_ubi &&
+	    !(fentry->flags & FILE_LIST_FLAG_UBI)) {
+		    fastboot_tx_print(f_fb, "INFOwriting UBI image to MTD device, "
+					    "add the 'u' ");
+		    fastboot_tx_print(f_fb, "INFOflag to the partition description");
+		    return 0;
+	}
+
+	if (!(fentry->flags & FILE_LIST_FLAG_UBI))
+		return 0;
+
+	if (IS_ERR(mtd)) {
+		fastboot_tx_print(f_fb, "FAILUBI flag given on non-MTD device");
+		return -EINVAL;
+	}
+
+	if (filetype == filetype_ubi) {
+		fastboot_tx_print(f_fb, "INFOThis is an UBI image...");
+		return 1;
+	} else {
+		fastboot_tx_print(f_fb, "FAILThis is no UBI image but %s",
+			file_type_to_string(filetype));
+		return -EINVAL;
+	}
+}
+
+static int fastboot_handle_sparse(struct f_fastboot *f_fb,
+				  struct file_list_entry *fentry)
+{
+	struct sparse_image_ctx *sparse;
+	void *buf = NULL;
+	int ret, fd;
+	unsigned int flags = O_RDWR;
+	int bufsiz = SZ_128K;
+	struct stat s;
+	struct mtd_info *mtd = NULL;
+
+	ret = stat(fentry->filename, &s);
+	if (ret) {
+		if (fentry->flags & FILE_LIST_FLAG_CREATE)
+			flags |= O_CREAT;
+		else
+			return ret;
+	}
+
+	fd = open(fentry->filename, flags);
+	if (fd < 0)
+		return -errno;
+
+	ret = fstat(fd, &s);
+	if (ret)
+		goto out_close_fd;
+
+	sparse = sparse_image_open(FASTBOOT_TMPFILE);
+	if (IS_ERR(sparse)) {
+		pr_err("Cannot open sparse image\n");
+		ret = PTR_ERR(sparse);
+		goto out_close_fd;
+	}
+
+	if (S_ISREG(s.st_mode)) {
+		ret = ftruncate(fd, sparse_image_size(sparse));
+		if (ret)
+			goto out;
+	}
+
+	buf = malloc(bufsiz);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (fentry->flags & FILE_LIST_FLAG_UBI) {
+		mtd = get_mtd(f_fb, fentry->filename);
+		if (IS_ERR(mtd)) {
+			ret = PTR_ERR(mtd);
+			goto out;
+		}
+	}
+
+	while (1) {
+		int retlen;
+		loff_t pos;
+
+		ret = sparse_image_read(sparse, buf, &pos, bufsiz, &retlen);
+		if (ret)
+			goto out;
+		if (!retlen)
+			break;
+
+		if (pos == 0) {
+			ret = check_ubi(f_fb, fentry, file_detect_type(buf, retlen));
+			if (ret < 0)
+				goto out;
+		}
+
+		if (fentry->flags & FILE_LIST_FLAG_UBI) {
+			if (pos == 0) {
+				ret = do_ubiformat(f_fb, mtd, NULL);
+				if (ret)
+					goto out;
+			}
+
+			ret = ubiformat_write(mtd, buf, retlen, pos);
+			if (ret)
+				goto out;
+		} else {
+			pos = lseek(fd, pos, SEEK_SET);
+			if (pos == -1) {
+				ret = -errno;
+				goto out;
+			}
+
+			ret = write_full(fd, buf, retlen);
+			if (ret < 0)
+				goto out;
+		}
+	}
+
+	ret = 0;
+
+out:
+	free(buf);
+	sparse_image_close(sparse);
+out_close_fd:
+	close(fd);
+
+	return ret;
+}
+
 static void cb_flash(struct usb_ep *ep, struct usb_request *req, const char *cmd)
 {
 	struct f_fastboot *f_fb = req->context;
@@ -706,33 +895,27 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req, const char *cmd
 
 	filename = fentry->filename;
 
-	if (filetype == filetype_ubi) {
-		int fd;
-		struct mtd_info_user meminfo;
-		struct ubiformat_args args = {
-			.yes = 1,
-			.image = FASTBOOT_TMPFILE,
-		};
-
-		fd = open(filename, O_RDONLY);
-		if (fd < 0)
-			goto copy;
+	if (filetype == filetype_android_sparse) {
+		ret = fastboot_handle_sparse(f_fb, fentry);
+		if (ret) {
+			fastboot_tx_print(f_fb, "FAILwriting sparse image: %s",
+					  strerror(-ret));
+			return;
+		}
 
-		ret = ioctl(fd, MEMGETINFO, &meminfo);
-		close(fd);
-		/* Not a MTD device, ubiformat is not a valid operation */
-		if (ret)
-			goto copy;
+		goto out;
+	}
 
-		fastboot_tx_print(f_fb, "INFOThis is an UBI image...");
+	ret = check_ubi(f_fb, fentry, filetype);
+	if (ret < 0)
+		return;
 
-		if (!IS_ENABLED(CONFIG_UBIFORMAT)) {
-			fastboot_tx_print(f_fb, "FAILubiformat is not available");
-			return;
-		}
+	if (ret > 0) {
+		struct mtd_info *mtd;
 
-		ret = ubiformat(meminfo.mtd, &args);
+		mtd = get_mtd(f_fb, fentry->filename);
 
+		ret = do_ubiformat(f_fb, mtd, FASTBOOT_TMPFILE);
 		if (ret) {
 			fastboot_tx_print(f_fb, "FAILwrite partition: %s", strerror(-ret));
 			return;
@@ -973,3 +1156,17 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
 	memset(req->buf, 0, EP_BUFFER_SIZE);
 	usb_ep_queue(ep, req);
 }
+
+static int fastboot_globalvars_init(void)
+{
+	globalvar_add_simple_int("usbgadget.fastboot_max_download_size",
+				 &fastboot_max_download_size, "%u");
+
+	return 0;
+}
+
+device_initcall(fastboot_globalvars_init);
+
+BAREBOX_MAGICVAR_NAMED(global_usbgadget_fastboot_max_download_size,
+		       global.usbgadget.fastboot_max_download_size,
+		       "Fastboot maximum download size");
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-01-12  8:03 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-11  7:50 fastboot sparse support Sascha Hauer
2018-01-11  7:50 ` [PATCH 1/7] fs: implement ftruncate Sascha Hauer
2018-01-11  7:50 ` [PATCH 2/7] ubiformat: Add ubiformat write function Sascha Hauer
2018-01-11  7:50 ` [PATCH 3/7] Documentation: USB gadget: Add section for partition description Sascha Hauer
2018-01-11  7:50 ` [PATCH 4/7] filetype: Add fastboot sparse format detection Sascha Hauer
2018-01-11  7:50 ` [PATCH 5/7] Add support for fastboot sparse images Sascha Hauer
2018-01-11  7:50 ` [PATCH 6/7] file_list: Add ubi flag Sascha Hauer
2018-01-11  7:50 ` [PATCH 7/7] usb: gadget: fastboot: Add sparse image support Sascha Hauer
2018-01-12  8:03   ` [PATCH] " Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox