image_types_gbmc_dynamic: Add class
This makes the image generation process more dynamic, rewriting the
device trees and u-boot images to reflect the final image layout. We no
longer write images at static offsets and instead append the u-boot,
then kernel, then rofs to the image. We finally leave an empty space
prior to the RWFS.
For 32MB images this requires that hoth support a dynamic mailbox
location.
This is currently not used by any platforms, and will be opted in as we
verify images per machine.
Tested: Verified on multiple npcm7xx platforms which are the first to be
enabled with this feature. The image layout is as expected and the
machine boots like normal. The hoth mailbox was verified to still work
as a valid communication channel.
Google-Bug-Id: 351901052
Change-Id: Ia8e93cd25204771987ce34d598186b40a846549c
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/classes/image_types_gbmc_dynamic.bbclass b/classes/image_types_gbmc_dynamic.bbclass
new file mode 100644
index 0000000..d867638
--- /dev/null
+++ b/classes/image_types_gbmc_dynamic.bbclass
@@ -0,0 +1,254 @@
+inherit image-artifact-names kernel-artifact-names
+
+add_partition_info_fitimage() {
+ cd ${DEPLOY_DIR_IMAGE}
+ dtb=$(basename ${KERNEL_DEVICETREE})
+ dts=${dtb%.*}.dts
+ sed -e 's,"linux.bin","fitImage-linux.bin-${KERNEL_FIT_LINK_NAME}",' \
+ -e "s,\"arch/.*.dtb\",\"$dtb\"," \
+ -i fitImage-its-${INITRAMFS_IMAGE_NAME}-${KERNEL_FIT_LINK_NAME}
+ dtc $dtb>$dts
+ rexpr() {
+ printf '/%s@[0-9]* {/,/};/s/reg = <.*>/reg = <(%d*1024) ((%d-%d)*1024)>/' $* $2
+ }
+ sed -e "$(rexpr u-boot ${FLASH_UBOOT_OFFSET} ${FLASH_IMAGE_DESC_OFFSET})" \
+ -e "$(rexpr image-descriptor ${FLASH_IMAGE_DESC_OFFSET} ${FLASH_KERNEL_OFFSET})" \
+ -e "$(rexpr kernel ${FLASH_KERNEL_OFFSET} ${FLASH_ROFS_OFFSET})" \
+ -e "$(rexpr rofs ${FLASH_ROFS_OFFSET} ${FLASH_EMPTY_OFFSET})" \
+ -e "$(rexpr hoth-mailbox ${FLASH_HOTH_MAILBOX_OFFSET} ${FLASH_HOTH_MAILBOX_END})" \
+ -e "$(rexpr hoth-update ${FLASH_HOTH_UPDATE_OFFSET} ${FLASH_HOTH_UPDATE_END})" \
+ -e "$(rexpr hoth-secondary ${FLASH_HOTH_SECONDARY_OFFSET} ${FLASH_HOTH_SECONDARY_END})" \
+ $dts >$dts.new
+ mv $dts.new $dts
+ dtc -O dtb -o $dtb.tmp $dts
+ mv $dtb.tmp $dtb
+ fit=$(readlink -f fitImage-${INITRAMFS_IMAGE_NAME}-${KERNEL_FIT_LINK_NAME})
+ oldsize=$(stat -c '%s' $fit)
+ uboot-mkimage -f fitImage-its-${INITRAMFS_IMAGE_NAME}-${KERNEL_FIT_LINK_NAME} $fit
+ if [ "$(stat -c '%s' $fit)" != $oldsize ]; then
+ echo "Rewritten FIT changed size"
+ exit 2
+ fi
+}
+
+python do_generate_static:gbmc() {
+ import subprocess
+
+ uboot_size = os.path.getsize(os.path.join(
+ d.getVar('DEPLOY_DIR_IMAGE', True), 'u-boot.%s' % d.getVar('UBOOT_SUFFIX', True)))
+ uboot_end = int((uboot_size + 65535) / 65536) * 64
+ d.setVar('FLASH_IMAGE_DESC_OFFSET', str(uboot_end))
+ imgdsc_end = uboot_end + 64
+ d.setVar('FLASH_KERNEL_OFFSET', str(imgdsc_end))
+ kernel_size = os.path.getsize(os.path.join(
+ d.getVar('DEPLOY_DIR_IMAGE', True), d.getVar('FLASH_KERNEL_IMAGE', True)))
+ kernel_end = imgdsc_end + int((kernel_size + 65535) / 65536) * 64
+ d.setVar('FLASH_ROFS_OFFSET', str(kernel_end))
+ rofs_size = os.path.getsize(os.path.join(
+ d.getVar('IMGDEPLOYDIR', True),
+ '%s.%s' % (d.getVar('IMAGE_LINK_NAME', True), d.getVar('IMAGE_BASETYPE', True))))
+ rofs_end = kernel_end + int((rofs_size + 65535) / 65536) * 64
+ d.setVar('FLASH_EMPTY_OFFSET', str(rofs_end))
+
+ has_hoth_secondary = d.getVar('ENABLE_HOTH_SECONDARY') == 'yes'
+ flash_size = int(d.getVar('FLASH_SIZE'))
+ rwfs_offset = int(d.getVar('FLASH_RWFS_OFFSET'))
+ rwfs_end = rwfs_offset + 3072
+ d.setVar('FLASH_RWFS_END', str(rwfs_end))
+ if flash_size == 32768:
+ # 32MB is special because the hoth update comes after RWFS
+ empty_end = rwfs_offset - 64
+ d.setVar('FLASH_EMPTY_END', str(empty_end))
+ d.setVar('FLASH_HOTH_MAILBOX_OFFSET', str(empty_end))
+ d.setVar('FLASH_HOTH_MAILBOX_END', str(rwfs_offset))
+ d.setVar('FLASH_HOTH_UPDATE_OFFSET', str(rwfs_end))
+ d.setVar('FLASH_HOTH_UPDATE_END', str(flash_size))
+ if has_hoth_secondary:
+ bb.fatal('32MB doesnt support secondary hoth update')
+ else:
+ empty_end = rwfs_offset - 1024
+ if has_hoth_secondary:
+ empty_end -= 1024
+ d.setVar('FLASH_EMPTY_END', str(empty_end))
+ d.setVar('FLASH_HOTH_SECONDARY_OFFSET', str(empty_end))
+ d.setVar('FLASH_HOTH_SECONDARY_END', str(empty_end + 1024))
+ d.setVar('FLASH_HOTH_UPDATE_OFFSET', str(rwfs_offset - 1024))
+ d.setVar('FLASH_HOTH_UPDATE_END', str(rwfs_offset))
+ d.setVar('FLASH_HOTH_MAILBOX_OFFSET', str(flash_size - 64))
+ d.setVar('FLASH_HOTH_MAILBOX_END', str(flash_size))
+
+ bb.build.exec_func("add_partition_info_fitimage", d)
+ bb.build.exec_func("do_mk_static_nor_image", d)
+
+ nor_image = os.path.join(d.getVar('IMGDEPLOYDIR', True),
+ '%s.static.mtd' % d.getVar('IMAGE_NAME', True))
+
+ written_ranges = [{"imgpath": "end", "start_kb": flash_size, "finish_kb": flash_size}]
+ def _append_image(imgpath, start_kb, finish_kb=0):
+ imgsize = os.path.getsize(imgpath)
+ finish_kb = int((start_kb * 1024 + imgsize + 65535) / 65536) * 64
+ bb.debug(2, 'Considering file size=' + str(imgsize) + ' name=' + imgpath)
+ bb.debug(2, 'Spanning start=' + str(start_kb) + 'K end=' + str(finish_kb) + 'K')
+ if int(start_kb / 64) * 64 != start_kb:
+ bb.fatal("Partitions must be 64K aligned")
+ for r in written_ranges:
+ if finish_kb > r["start_kb"] and start_kb < r["finish_kb"]:
+ bb.fatal("Paritions '%s' and '%s' overlap" % (r["imgpath"], imgpath))
+
+ written_ranges.append({"imgpath": imgpath, "start_kb": start_kb, "finish_kb": finish_kb})
+ subprocess.check_call(['dd', 'bs=1k', 'conv=notrunc', 'seek=%d' % start_kb,
+ 'if=%s' % imgpath, 'of=%s' % nor_image])
+
+ _append_image(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True),
+ 'u-boot.%s' % d.getVar('UBOOT_SUFFIX',True)),
+ int(d.getVar('FLASH_UBOOT_OFFSET', True)))
+
+ _append_image(os.path.join(d.getVar('DEPLOY_DIR_IMAGE', True),
+ d.getVar('FLASH_KERNEL_IMAGE', True)),
+ int(d.getVar('FLASH_KERNEL_OFFSET', True)))
+
+ _append_image(os.path.join(d.getVar('IMGDEPLOYDIR', True),
+ '%s.%s' % (
+ d.getVar('IMAGE_LINK_NAME', True),
+ d.getVar('IMAGE_BASETYPE', True))),
+ int(d.getVar('FLASH_ROFS_OFFSET', True)))
+
+ _append_image(os.path.join(d.getVar('IMGDEPLOYDIR', True),
+ '%s.%s' % (
+ d.getVar('IMAGE_LINK_NAME', True),
+ d.getVar('OVERLAY_BASETYPE', True))),
+ int(d.getVar('FLASH_RWFS_OFFSET', True)))
+
+ bb.build.exec_func("do_mk_static_symlinks", d)
+}
+
+python do_generate_layout:gbmc() {
+}
+
+python do_generate_static:append:hoth() {
+ mailbox_str = '_HVNMAIL'
+ mailbox_length = 1024
+ mailbox_bytes = mailbox_str * int(mailbox_length / len(mailbox_str))
+ with open(nor_image, 'r+') as mailbox:
+ mailbox.seek(int(d.getVar('FLASH_HOTH_MAILBOX_OFFSET'))*1024)
+ mailbox.write(mailbox_bytes)
+
+ import time
+ import json
+
+ def convertPart(name, startKb, endKb, static=False, wp=False, persist=False):
+ regionTypes = []
+ extraAttrs = {}
+ if static:
+ regionTypes.append('STATIC')
+ if wp:
+ regionTypes.append('WRITE_PROTECTED')
+ if persist:
+ regionTypes.append('PERSISTENT')
+ if name == 'hoth_mailbox':
+ regionTypes.append('MAILBOX')
+ extraAttrs['mailbox_length'] = mailbox_length
+
+ start = int(startKb) * 1024
+ end = int(endKb) * 1024
+
+ return {
+ 'name': name,
+ 'offset': start,
+ 'length': end - start,
+ 'region_type': regionTypes,
+ **extraAttrs,
+ }
+
+ region = [
+ convertPart(
+ 'u_boot',
+ d.getVar('FLASH_UBOOT_OFFSET'),
+ d.getVar('FLASH_IMAGE_DESC_OFFSET'),
+ static=True,
+ wp=True),
+ convertPart(
+ 'image_descriptor',
+ d.getVar('FLASH_IMAGE_DESC_OFFSET'),
+ d.getVar('FLASH_KERNEL_OFFSET'),
+ static=True,
+ wp=True),
+ convertPart(
+ 'kernel',
+ d.getVar('FLASH_KERNEL_OFFSET'),
+ d.getVar('FLASH_ROFS_OFFSET'),
+ static=True,
+ wp=True),
+ convertPart(
+ 'rofs',
+ d.getVar('FLASH_ROFS_OFFSET'),
+ d.getVar('FLASH_EMPTY_OFFSET'),
+ static=True,
+ wp=True),
+ convertPart(
+ 'empty',
+ d.getVar('FLASH_EMPTY_OFFSET'),
+ d.getVar('FLASH_EMPTY_END'),
+ wp=True),
+ convertPart(
+ 'rwfs',
+ d.getVar('FLASH_RWFS_OFFSET'),
+ d.getVar('FLASH_RWFS_END'),
+ persist=True),
+ convertPart(
+ 'hoth_update',
+ d.getVar('FLASH_HOTH_UPDATE_OFFSET'),
+ d.getVar('FLASH_HOTH_UPDATE_END')),
+ convertPart(
+ 'hoth_mailbox',
+ d.getVar('FLASH_HOTH_MAILBOX_OFFSET'),
+ d.getVar('FLASH_HOTH_MAILBOX_END')),
+ ] + ([
+ convertPart(
+ 'hoth_secondary',
+ d.getVar('FLASH_HOTH_SECONDARY_OFFSET'),
+ d.getVar('FLASH_HOTH_SECONDARY_END')),
+ ] if d.getVar('ENABLE_HOTH_SECONDARY') == 'yes' else [])
+
+ machine = d.getVar('MACHINE')
+ platform = d.getVar('PLATFORM')
+ name = '{} {} image'.format(machine, d.getVar('DISTRO'))
+ version = d.getVar('GBMC_VERSION').split('.')
+
+ if not platform:
+ raise NameError('PLATFORM not found, unable to generate layout, stopping build')
+
+ layout = {
+ 'name': name,
+ 'major': int(version[0]),
+ 'minor': int(version[1]),
+ 'point': int(version[2]),
+ 'subpoint': int(version[3]),
+ 'platform': platform,
+ 'flash_capacity': int(d.getVar('FLASH_SIZE')) * 1024,
+ 'build_timestamp': int(time.time()),
+ 'region': sorted(region, key=lambda r: r["offset"]),
+ }
+
+ dir = d.getVar('DEPLOY_DIR_IMAGE')
+ os.makedirs(dir, exist_ok=True)
+ path = os.path.join(dir, 'cr51-image-layout.json')
+ with open(path, 'w') as f:
+ json.dump(layout, f, sort_keys=True, indent=4)
+}
+do_generate_static[depends] += " \
+ u-boot-tools-native:do_populate_sysroot \
+ dtc-native:do_populate_sysroot \
+ "
+
+do_prepare_bootloaders:append:npcm7xx() {
+ merged=${DEPLOY_DIR_IMAGE}/${UBOOT_BINARY}.${MERGED_SUFFIX}
+ msize=$(stat -c '%s' $merged)
+ # Partitions are 64K aligned, with u-boot then (64K) image descriptor then kernel
+ kern_off=$(expr '(' $msize + 65535 ')' / 65536 '*' 65536 + 65536)
+ # Match the uimage_flash_addr format below with an 0x80000000 base
+ addr=$(printf '%08x' $(expr 2147483648 + $kern_off))
+ grep -q 'uimage_flash_addr=80200000' $merged
+ sed -i "s,uimage_flash_addr=80200000,uimage_flash_addr=$addr," $merged
+ echo "Set uimage_flash_addr to $addr"
+}