images: Add support for generating ubi images

Add new image types to enable selection of a two partition mtd
image: u-boot, and remaining components in a ubi image.

UBI enables advanced volume management for flash devices.

Resolves: openbmc/openbmc#1941

Change-Id: Ia6ffa96877943c73c14aba76f8fe9533d22b3aa5
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/meta-phosphor/classes/image_types_phosphor.bbclass b/meta-phosphor/classes/image_types_phosphor.bbclass
index 51259df..565e43c 100644
--- a/meta-phosphor/classes/image_types_phosphor.bbclass
+++ b/meta-phosphor/classes/image_types_phosphor.bbclass
@@ -13,38 +13,73 @@
 
 # Phosphor image types
 #
-# Phosphor OpenBMC supports a fixed partition mtd layout.
+# Phosphor OpenBMC supports a fixed partition mtd layout,
+# A dynamic mtd with ubi layout, and a tar file for use with
+# The reference BMC software update implementation.
 
 # Image composition
 FLASH_KERNEL_IMAGE ?= "fitImage-${INITRAMFS_IMAGE}-${MACHINE}.bin"
 IMAGE_BASETYPE ?= "squashfs-xz"
 OVERLAY_BASETYPE ?= "jffs2"
+FLASH_UBI_BASETYPE ?= "${IMAGE_BASETYPE}"
+FLASH_UBI_OVERLAY_BASETYPE ?= "ubifs"
 
-IMAGE_TYPES += "mtd-static mtd-static-alltar mtd-static-tar"
+IMAGE_TYPES += "overlay mtd-static mtd-static-alltar mtd-static-tar mtd-ubi mtd-ubi-tar"
 
+IMAGE_TYPEDEP_overlay = "${IMAGE_BASETYPE}"
 IMAGE_TYPEDEP_mtd-static = "${IMAGE_BASETYPE}"
 IMAGE_TYPEDEP_mtd-static-tar = "${IMAGE_BASETYPE}"
 IMAGE_TYPEDEP_mtd-static-alltar = "mtd-static"
-IMAGE_TYPES_MASKED += "mtd-static mtd-static-alltar mtd-static-tar"
+IMAGE_TYPEDEP_mtd-ubi = "${FLASH_UBI_BASETYPE}"
+IMAGE_TYPEDEP_mtd-ubi-tar = "${FLASH_UBI_BASETYPE}"
+IMAGE_TYPES_MASKED += "overlay mtd-static mtd-static-alltar mtd-static-tar mtd-ubi mtd-ubi-tar"
 
-# Flash characteristics
+# Flash characteristics in KB unless otherwise noted
 FLASH_SIZE ?= "32768"
+FLASH_PEB_SIZE ?= "64"
+# Flash page and overhead sizes in bytes
+FLASH_PAGE_SIZE ?= "1"
+FLASH_NOR_UBI_OVERHEAD ?= "64"
 
 # Fixed partition offsets
 FLASH_UBOOT_OFFSET ?= "0"
 FLASH_KERNEL_OFFSET ?= "512"
+FLASH_UBI_OFFSET ?= "${FLASH_KERNEL_OFFSET}"
 FLASH_ROFS_OFFSET ?= "4864"
 FLASH_RWFS_OFFSET ?= "28672"
 
+# UBI volume sizes in KB unless otherwise noted.
+FLASH_UBI_RWFS_SIZE ?= "4096"
+FLASH_UBI_RWFS_TXT_SIZE ?= "4MiB"
+
+python() {
+    # Compute rwfs LEB count and LEB size.
+    page_size = d.getVar('FLASH_PAGE_SIZE', True)
+    nor_overhead_size = d.getVar('FLASH_NOR_UBI_OVERHEAD', True)
+    overhead_size = max(int(page_size), int(nor_overhead_size))
+    peb_size = d.getVar('FLASH_PEB_SIZE', True)
+    leb_size = (int(peb_size) * 1024) - (2 * overhead_size)
+    d.setVar('FLASH_LEB_SIZE', str(leb_size)) # In bytes
+
+    rwfs_size = d.getVar('FLASH_UBI_RWFS_SIZE', True)
+    rwfs_size = int(rwfs_size) * 1024
+    lebs = int((rwfs_size + leb_size - 1) / leb_size) # Rounding up
+    d.setVar('FLASH_UBI_RWFS_LEBS', str(lebs))
+}
+
 # Allow rwfs mkfs configuration through OVERLAY_MKFS_OPTS and OVERRIDES. However,
 # avoid setting 'ext4' or 'jffs2' in OVERRIDES as such raw filesystem types are
 # reserved for the primary image (and setting them currently breaks the build).
 # Instead, prefix the overlay override value with 'rwfs-' to avoid collisions.
 DISTROOVERRIDES .= ":static-rwfs-${OVERLAY_BASETYPE}"
+DISTROOVERRIDES .= ":ubi-rwfs-${FLASH_UBI_OVERLAY_BASETYPE}"
 
 JFFS2_RWFS_CMD = "mkfs.jffs2 --root=jffs2 --faketime --output=rwfs.jffs2"
+UBIFS_RWFS_CMD = "mkfs.ubifs -r ubifs -c ${FLASH_UBI_RWFS_LEBS} -m ${FLASH_PAGE_SIZE} -e ${FLASH_LEB_SIZE} rwfs.ubifs"
 
 FLASH_STATIC_RWFS_CMD_static-rwfs-jffs2 = "${JFFS2_RWFS_CMD}"
+FLASH_UBI_RWFS_CMD_ubi-rwfs-jffs2 = "${JFFS2_RWFS_CMD}"
+FLASH_UBI_RWFS_CMD_ubi-rwfs-ubifs = "${UBIFS_RWFS_CMD}"
 
 mk_nor_image() {
 	image_dst="$1"
@@ -75,6 +110,70 @@
         mtd-utils-native:do_populate_sysroot \
         "
 
+do_generate_rwfs_ubi() {
+	make_rwfs ${FLASH_UBI_OVERLAY_BASETYPE} "${FLASH_UBI_RWFS_CMD}"
+}
+do_generate_rwfs_ubi[dirs] = " ${S}/ubi"
+do_generate_rwfs_ubi[depends] += " \
+        mtd-utils-native:do_populate_sysroot \
+        "
+
+add_volume() {
+	config_file=$1
+	vol_id=$2
+	vol_type=$3
+	vol_name=$4
+	image=$5
+	vol_size=$6
+
+	echo \[$vol_name\] >> $config_file
+	echo mode=ubi >> $config_file
+	echo image=$image >> $config_file
+	echo vol_type=$vol_type >> $config_file
+	echo vol_name=$vol_name >> $config_file
+	echo vol_id=$vol_id >> $config_file
+	if [ ! -z $vol_size ]; then
+		echo vol_size=$vol_size >> $config_file
+	fi
+}
+
+do_generate_ubi() {
+	cfg=ubinize-${IMAGE_NAME}.cfg
+
+	rm -f $cfg ubi-img
+
+	# Construct the ubinize config file
+	add_volume $cfg 0 static kernel0 \
+		${DEPLOY_DIR_IMAGE}/${FLASH_KERNEL_IMAGE}
+
+	add_volume $cfg 1 static rofs0 \
+		${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.${FLASH_UBI_BASETYPE}
+
+	add_volume $cfg 2 dynamic rwfs rwfs.${FLASH_UBI_OVERLAY_BASETYPE} ${FLASH_UBI_RWFS_TXT_SIZE}
+
+	# Build the ubi partition image
+	ubinize -p ${FLASH_PEB_SIZE}KiB -m ${FLASH_PAGE_SIZE} -o ubi-img $cfg
+
+	# Concatenate the uboot and ubi partitions
+	mk_nor_image ${IMGDEPLOYDIR}/${IMAGE_NAME}.ubi.mtd ${FLASH_SIZE}
+	dd bs=1k conv=notrunc seek=${FLASH_UBOOT_OFFSET} \
+		if=${DEPLOY_DIR_IMAGE}/u-boot.${UBOOT_SUFFIX} \
+		of=${IMGDEPLOYDIR}/${IMAGE_NAME}.ubi.mtd
+	dd bs=1k conv=notrunc seek=${FLASH_UBI_OFFSET} \
+		if=ubi-img \
+		of=${IMGDEPLOYDIR}/${IMAGE_NAME}.ubi.mtd
+
+	cd ${IMGDEPLOYDIR}
+	ln -sf ${IMAGE_NAME}.ubi.mtd ${IMGDEPLOYDIR}/${IMAGE_LINK_NAME}.ubi.mtd
+}
+do_generate_ubi[dirs] = "${S}/ubi"
+do_generate_ubi[depends] += " \
+        ${PN}:do_image_${@d.getVar('FLASH_UBI_BASETYPE', True).replace('-', '_')} \
+        virtual/kernel:do_deploy \
+        u-boot:do_populate_sysroot \
+        mtd-utils-native:do_populate_sysroot \
+        "
+
 do_generate_static() {
 	# Assemble the flash image
 	mk_nor_image ${IMGDEPLOYDIR}/${IMAGE_NAME}.static.mtd ${FLASH_SIZE}
@@ -168,6 +267,17 @@
         "
 do_generate_static_tar[vardepsexclude] = "DATETIME"
 
+do_generate_ubi_tar() {
+	ln -sf ${S}/MANIFEST MANIFEST
+	make_tar_of_images ${FLASH_UBI_OVERLAY_BASETYPE} ${FLASH_UBI_BASETYPE} ubi MANIFEST
+}
+do_generate_ubi_tar[dirs] = " ${S}/ubi"
+do_generate_ubi_tar[depends] += " \
+        ${PN}:do_image_${@d.getVar('FLASH_UBI_BASETYPE', True).replace('-', '_')} \
+        virtual/kernel:do_deploy \
+        u-boot:do_populate_sysroot \
+        "
+
 python do_generate_phosphor_manifest() {
     import configparser
     import io
@@ -193,6 +303,7 @@
 
 addtask generate_phosphor_manifest after do_rootfs
 addtask generate_rwfs_static after do_rootfs
+addtask generate_rwfs_ubi after do_rootfs
 
 python() {
     types = d.getVar('IMAGE_FSTYPES', True).split()
@@ -212,4 +323,15 @@
                 'do_generate_static_tar',
                 'do_image_complete',
                 'do_generate_rwfs_static', d)
+
+    if 'mtd-ubi' in types:
+        bb.build.addtask(
+                'do_generate_ubi',
+                'do_image_complete',
+                'do_generate_rwfs_ubi', d)
+    if 'mtd-ubi-tar' in types:
+        bb.build.addtask(
+                'do_generate_ubi_tar',
+                'do_image_complete',
+                'do_generate_rwfs_ubi do_generate_phosphor_manifest', d)
 }