Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions classes-recipe/dtb-fit-image.bbclass
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
inherit kernel-arch uboot-config
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uboot-config?


require conf/image-fitimage.conf

DEPENDS += "\
u-boot-tools-native dtc-native \
qcom-dtb-metadata \
"

# Initialize root node
python fitimage_init_rootnode() {
import sys, os
file_path = d.getVar('FILE')
customfit = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(file_path))), 'lib')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use pathlib instead of this nested dirname calls.

if os.path.isdir(customfit) and customfit not in sys.path:
sys.path.insert(0, customfit)
bb.note("Added to sys.path (parse-time): %s" % customfit)
import oe.types
from qcom_fitimage import QcomItsNodeRoot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move import lines together to the initial ones, add an empty line after.

root_node = QcomItsNodeRoot(
d.getVar("FIT_DESC"), d.getVar("FIT_ADDRESS_CELLS"),
d.getVar('HOST_PREFIX'), d.getVar('UBOOT_ARCH'), d.getVar("FIT_CONF_PREFIX"),
oe.types.boolean(d.getVar('UBOOT_SIGN_ENABLE')), d.getVar("UBOOT_SIGN_KEYDIR"),
d.getVar("UBOOT_MKIMAGE"), d.getVar("UBOOT_MKIMAGE_DTCOPTS"),
d.getVar("UBOOT_MKIMAGE_SIGN"), d.getVar("UBOOT_MKIMAGE_SIGN_ARGS"),
d.getVar('FIT_HASH_ALG'), d.getVar('FIT_SIGN_ALG'), d.getVar('FIT_PAD_ALG'),
d.getVar('UBOOT_SIGN_KEYNAME'),
oe.types.boolean(d.getVar('FIT_SIGN_INDIVIDUAL')), d.getVar('UBOOT_SIGN_IMG_KEYNAME')
)
d.setVar("__fit_root_node", root_node)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a more standard OE var, use caps here.

bb.debug(1, "Global root_node initialized")
}

# Add DTB section
python fitimage_add_dtb_section() {
import shutil, os
deploydir = d.getVar('DEPLOY_DIR_IMAGE')
kerneldeploydir = d.getVar("DEPLOYDIR")
root_node = d.getVar("__fit_root_node")
if not root_node:
bb.fatal("root_node not initialized.")

# Pass additional options
root_node.set_extra_opts(d.getVar("UBOOT_MKIMAGE_EXTRA_OPTS"))
kernel_devicetree = d.getVar('KERNEL_DEVICETREE')

# Handle qcom metadata
kernel_devicetree = 'qcom-metadata.dtb ' + kernel_devicetree
shutil.copy(os.path.join(deploydir, 'qcom-metadata.dtb'), os.path.join(kerneldeploydir, 'qcom-metadata.dtb'))

if kernel_devicetree:
for dtb in kernel_devicetree.split():
dtb_name = os.path.basename(dtb)
dtb_base = os.path.splitext(dtb_name)[0]
compatible = d.getVarFlag("FIT_DTB_COMPATIBLE", dtb_base) or ""
abs_path = os.path.join(deploydir, dtb_name)
root_node.fitimage_emit_section_dtb(dtb_name, dtb_name,
d.getVar("UBOOT_DTB_LOADADDRESS"), d.getVar("UBOOT_DTBO_LOADADDRESS"), True,
compatible_str=compatible, dtb_abspath=abs_path)
}

# Modify ITS file
python fitimage_modify_its_file() {
import re

deploy_dir = d.getVar("DEPLOYDIR")
itsfile = os.path.join(deploy_dir, "fit-image.its")

with open(itsfile, 'r') as f:
content = f.read()

# Replace type as qcom_metadata for qcom-dtb-metadata
content = re.sub(r'(fdt-qcom-metadata.dtb\s*\{[^}]*?)type\s*=\s*"flat_dt";',
r'\1type = "qcom_metadata";', content, flags=re.DOTALL)

# Remove conf-0 entry which corresponds to fdt-0
content = re.sub(r'conf-0\s*\{[^}]*\};', '', content, flags=re.DOTALL)

with open(itsfile, 'w') as f:
f.write(content)
}

# Generate ITS and FIT image
python fitimage_generate_its() {
deploy_dir = d.getVar("DEPLOYDIR")
itsfile = os.path.join(deploy_dir, "fit-image.its")
fitname = os.path.join(deploy_dir, "fitImage")

bb.build.exec_func('fitimage_init_rootnode', d)
bb.build.exec_func('fitimage_add_dtb_section', d)
root_node = d.getVar("__fit_root_node")
root_node.fitimage_emit_section_config(d.getVar("FIT_CONF_DEFAULT_DTB"))
root_node.write_its_file(itsfile)
bb.build.exec_func('fitimage_modify_its_file', d)
root_node.run_mkimage_assemble(itsfile, fitname)
root_node.run_mkimage_sign(fitname)
}

do_compile_qcom_fitimage[depends] += "qcom-dtb-metadata:do_deploy"

python do_compile_qcom_fitimage() {
bb.build.exec_func('fitimage_generate_its', d)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to create all these functions here? It is fine to have it all under a single do_compile_qcom_fitimage function, similar to the way it is done at meta/classes-recipe/kernel-fit-image.bbclass.



do_deploy_qcom_fitimage() {
install -m 0644 "${DEPLOYDIR}/fitImage" "${DEPLOY_DIR_IMAGE}/fitImage"
install -m 0644 "${DEPLOYDIR}/fit-image.its" "${DEPLOY_DIR_IMAGE}/fit-image.its"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's how the normal kernel-fit is also deployed, pick a different name for both the binary and its.

}
addtask compile_qcom_fitimage after do_deploy
addtask deploy_qcom_fitimage after do_compile_qcom_fitimage do_deploy
11 changes: 9 additions & 2 deletions classes/linux-qcom-dtbbin.bbclass
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
# SPDX-License-Identifier: BSD-3-Clause-Clear
#

inherit dtb-fit-image

DTBBIN_DEPLOYDIR = "${WORKDIR}/qcom_dtbbin_deploy-${PN}"
DTBBIN_SIZE ?= "4096"
DTBBIN_SIZE ?= "65536"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will also impact the size of every dtb vfat image we generate.


do_qcom_dtbbin_deploy[depends] += "dosfstools-native:do_populate_sysroot mtools-native:do_populate_sysroot"
do_qcom_dtbbin_deploy[cleandirs] = "${DTBBIN_DEPLOYDIR}"
Expand All @@ -21,8 +23,13 @@ do_qcom_dtbbin_deploy() {
mcopy -i "${DTBBIN_DEPLOYDIR}/dtb-${dtb_base_name}-image.vfat" -vsmpQ ${DTBBIN_DEPLOYDIR}/$dtb_base_name/* ::/
rm -rf ${DTBBIN_DEPLOYDIR}/$dtb_base_name
done
# Generate qclinux_fit.img along side combined-dtb.dtb
if [ -f "${DEPLOY_DIR_IMAGE}/fitImage" ]; then
mkfs.vfat -S ${QCOM_VFAT_SECTOR_SIZE} -C ${DTBBIN_DEPLOYDIR}/multi-dtb.vfat ${DTBBIN_SIZE}
mcopy -i "${DTBBIN_DEPLOYDIR}/multi-dtb.vfat" -vsmpQ ${DEPLOY_DIR_IMAGE}/fitImage ::/qclinux_fit.img
fi
}
addtask qcom_dtbbin_deploy after do_populate_sysroot do_packagedata before do_deploy
addtask qcom_dtbbin_deploy after do_populate_sysroot do_packagedata do_deploy do_deploy_qcom_fitimage before do_build

# Setup sstate, see deploy.bbclass
SSTATETASKS += "do_qcom_dtbbin_deploy"
Expand Down
13 changes: 13 additions & 0 deletions conf/machine/include/qcom-common.inc
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,16 @@ EFI_PROVIDER = "systemd-boot"

# Unified Kernel Image (UKI) name
EFI_LINUX_IMG ?= "linux-${MACHINE}.efi"

# Variables to generate ITS file
UBOOT_CONFIG ??= "qcom"
UBOOT_CONFIG[qcom] ?= "qcom_defconfig"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this related to fit at all?

The only thing we're using from u-boot is mkimage.


# Pass additional options to mkimage command
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should instead explain why the extra options are needed here.

UBOOT_MKIMAGE_EXTRA_OPTS = "-E -B 0x0001000"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?


# Set default configuration
FIT_CONF_DEFAULT_DTB = "1"

# Set hash algorithm
FIT_HASH_ALG = ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These options will also affect users using kernel-fit (e.g. u-boot users).

2 changes: 2 additions & 0 deletions conf/machine/iq-8275-evk.conf
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ QCOM_BOOT_FILES_SUBDIR = "qcs8300"
QCOM_PARTITION_FILES_SUBDIR ?= "partitions/iq-8275-evk/ufs"

QCOM_BOOT_FIRMWARE = "firmware-qcom-boot-qcs8300"

FIT_DTB_COMPATIBLE[monaco-evk] = "qcom,qcs8275-iot"
2 changes: 2 additions & 0 deletions conf/machine/iq-9075-evk.conf
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ QCOM_BOOT_FILES_SUBDIR = "qcs9100"
QCOM_PARTITION_FILES_SUBDIR ?= "partitions/iq-9075-evk/ufs"

QCOM_BOOT_FIRMWARE = "firmware-qcom-boot-qcs9100"

FIT_DTB_COMPATIBLE[lemans-evk] = "qcom,qcs9075-iot qcom,qcs9075v2-iot"
2 changes: 2 additions & 0 deletions conf/machine/qcm6490-idp.conf
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ QCOM_BOOT_FILES_SUBDIR = "qcm6490"

QCOM_BOOT_FIRMWARE = "firmware-qcom-boot-qcs6490"
QCOM_PARTITION_FILES_SUBDIR ?= "partitions/qcm6490-idp/ufs"

FIT_DTB_COMPATIBLE[qcm6490-idp] = "qcom,qcm6490-idp"
2 changes: 2 additions & 0 deletions conf/machine/qcs615-adp-air.conf
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS += " \
QCOM_CDT_FILE = "cdt_adp_air_sa6155p"
QCOM_BOOT_FILES_SUBDIR = "qcs615"
QCOM_PARTITION_FILES_SUBDIR ?= "partitions/qcs615-adp-air/ufs"

FIT_DTB_COMPATIBLE[qcs615-ride] = "qcom,qcs615-adp qcom,qcs615v1.1-adp"
2 changes: 2 additions & 0 deletions conf/machine/qcs8300-ride-sx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ QCOM_BOOT_FILES_SUBDIR = "qcs8300"
QCOM_PARTITION_FILES_SUBDIR ?= "partitions/qcs8300-ride-sx/ufs"

QCOM_BOOT_FIRMWARE = "firmware-qcom-boot-qcs8300"

FIT_DTB_COMPATIBLE[qcs8300-ride] = "qcom,qcs8300-adp"
5 changes: 5 additions & 0 deletions conf/machine/qcs9100-ride-sx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ QCOM_BOOT_FILES_SUBDIR = "qcs9100"
QCOM_PARTITION_FILES_SUBDIR ?= "partitions/qcs9100-ride-sx/ufs"

QCOM_BOOT_FIRMWARE = "firmware-qcom-boot-qcs9100"

FIT_DTB_COMPATIBLE[qcs9100-ride] = "qcom,qcs9100-qam qcom,qcs9100v2-qam"
FIT_DTB_COMPATIBLE[qcs9100-ride-r3] = "qcom,qcs9100-qamr2 qcom,qcs9100v2-qamr2"
FIT_DTB_COMPATIBLE[sa8775p-ride] = "qcom,sa8775p-qam qcom,sa8775pv2-qam"
FIT_DTB_COMPATIBLE[sa8775p-ride-r3] = "qcom,sa8775p-qamr2 qcom,sa8775pv2-qamr2"
3 changes: 3 additions & 0 deletions conf/machine/rb3gen2-core-kit.conf
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ QCOM_BOOT_FILES_SUBDIR = "qcm6490"
QCOM_PARTITION_FILES_SUBDIR ?= "partitions/qcs6490-rb3gen2/ufs"

QCOM_BOOT_FIRMWARE = "firmware-qcom-boot-qcs6490"

FIT_DTB_COMPATIBLE[qcs6490-rb3gen2-vision-mezzanine] = "qcom,qcs6490-iot-subtype2"
FIT_DTB_COMPATIBLE[qcs6490-rb3gen2] = "qcom,qcs6490-iot"
131 changes: 131 additions & 0 deletions lib/qcom_fitimage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather rename this file to be specific to DTB (e.g. qcom_dtb_fitimage or similar), as this will later confuse people since we do also expect u-boot users to leverage the traditional fit image from oe-core (making it just qcom_fit gives the impression that this is just a qcom implementation of the generic fit).

# SPDX-License-Identifier: BSD-3-Clause-Clear
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are extending fitimage.py from OE, which is GPL-2.0-only, we should align the license here.

#
# This file contains functions for Qualcomm specific DTB-only fitimage generation,
# which imports classes from OE-Core fitimage.py and enhances to meet Qualcomm FIT
# specifications.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


import os
import shlex
import subprocess
import bb
from typing import Tuple
import oe.fitimage
from oe.fitimage import ItsNodeRootKernel, get_compatible_from_dtb

class QcomItsNodeRoot(ItsNodeRootKernel):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to document the Qualcomm-specific requirements for DTB-only FIT images to be able to properly review this series of patches.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, it seems to be documented here https://github.com/qualcomm-linux/qcom-dtb-metadata/blob/main/Documentation.md. it should have been clear in the PR :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment to this class explaining why it needs to extend ItsNodeRootKernel.


def __init__(self, description, address_cells, host_prefix, arch, conf_prefix,
sign_enable=False, sign_keydir=None,
mkimage=None, mkimage_dtcopts=None,
mkimage_sign=None, mkimage_sign_args=None,
hash_algo=None, sign_algo=None, pad_algo=None,
sign_keyname_conf=None,
sign_individual=False, sign_keyname_img=None):
# Call parent constructor
super().__init__(description, address_cells, host_prefix, arch, conf_prefix,
sign_enable, sign_keydir, mkimage, mkimage_dtcopts,
mkimage_sign, mkimage_sign_args, hash_algo, sign_algo,
pad_algo, sign_keyname_conf, sign_individual, sign_keyname_img)

self._mkimage_extra_opts = []
self._dtbs = []

def set_extra_opts(self, mkimage_extra_opts):
self._mkimage_extra_opts = shlex.split(mkimage_extra_opts) if mkimage_extra_opts else []

# Override DTB section to allow compatible_override
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this a python-based function specific comment instead.

def fitimage_emit_section_dtb(self, dtb_id, dtb_path, dtb_loadaddress=None,
dtbo_loadaddress=None, add_compatible=False,
compatible_str=None, dtb_abspath=None):
load = None
dtb_ext = os.path.splitext(dtb_path)[1]
if dtb_ext == ".dtbo":
if dtbo_loadaddress:
load = dtbo_loadaddress
elif dtb_loadaddress:
load = dtb_loadaddress

opt_props = {
"data": '/incbin/("' + dtb_path + '")',
"arch": self._arch
}
if load:
opt_props["load"] = f"<{load}>"

compatibles = None
if add_compatible:
if compatible_str:
compatibles = str(compatible_str).split()
elif dtb_ext != ".dtbo":
compatibles = get_compatible_from_dtb(dtb_abspath)

dtb_node = self.its_add_node_dtb(
"fdt-" + dtb_id,
"Flattened Device Tree blob",
"flat_dt",
"none",
opt_props,
compatibles
)
self._dtbs.append((dtb_node, compatibles or []))

def fitimage_emit_section_config(self, default_dtb_image=None):
if self._dtbs:
counter = 0
for entry in self._dtbs:
if isinstance(entry, tuple) and len(entry) == 2:
dtb_node, compatibles = entry
if compatibles:
for comp in compatibles:
conf_name = f"{self._conf_prefix}{counter}"
counter += 1
self._fitimage_emit_one_section_config(conf_name, dtb_node)
conf_node = self.configurations.sub_nodes[-1]
conf_node.add_property('compatible', comp)
else:
conf_name = f"{self._conf_prefix}{counter}"
counter += 1
self._fitimage_emit_one_section_config(conf_name, dtb_node)
else:
dtb_node = entry
conf_name = f"{self._conf_prefix}{counter}"
counter += 1
self._fitimage_emit_one_section_config(conf_name, dtb_node)
else:
# Currently exactly one kernel is supported.
self._fitimage_emit_one_section_config(self._conf_prefix + "1")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kernel?


default_conf = self.configurations.sub_nodes[0].name
if default_dtb_image and self._dtbs:
default_conf = self._conf_prefix + default_dtb_image
self.configurations.add_property('default', default_conf)

# Override mkimage assemble to inject extra opts
def run_mkimage_assemble(self, itsfile, fitfile):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change can probably go directly to oe-core upstream, you are just adding support for extra mkimage arguments.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, replied asking for clarification for the reason why we need to customize the options here, it is not clear even in this PR.

cmd = [self._mkimage, *self._mkimage_extra_opts, '-f', itsfile, fitfile]
if self._mkimage_dtcopts:
cmd.insert(1, '-D')
cmd.insert(2, self._mkimage_dtcopts)

bb.note(f"Running mkimage with extra opts: {' '.join(cmd)}")

try:
subprocess.run(cmd, check=True, capture_output=True)
except subprocess.CalledProcessError as e:
bb.fatal(
f"Command '{' '.join(cmd)}' failed with return code {e.returncode}\n"
f"stdout: {e.stdout.decode()}\n"
f"stderr: {e.stderr.decode()}\n"
f"itsfile: {os.path.abspath(itsfile)}"
)

def get_compatible_from_dtb(dtb_path, fdtget_path="fdtget"):
compatible = None
cmd = [fdtget_path, "-t", "s", dtb_path, "/", "compatible"]
try:
ret = subprocess.run(cmd, check=True, capture_output=True, text=True)
compatible = ret.stdout.strip().split()
except subprocess.CalledProcessError:
compatible = None
return compatible
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you just duplicated this function?

25 changes: 25 additions & 0 deletions recipes-kernel/linux/qcom-dtb-metadata_git.bb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
SUMMARY = "Build qcom-metadata.dtb from vendored qcom-dtb-metadata"
HOMEPAGE = "https://github.com/qualcomm-linux/qcom-dtb-metadata"

LICENSE = "BSD-3-Clause-Clear"
LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=2998c54c288b081076c9af987bdf4838"

DEPENDS = "dtc-native"

SRC_URI = "git://github.com/qualcomm-linux/qcom-dtb-metadata.git;branch=main;protocol=https"

SRCREV = "6b9e4b9c093cba36a80035af103015f0a7d3f9fc"

PV = "0.1+git"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This revision is exactly the v0.1 tag, no need for +git.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also rename the recipe to be specific to the version used, which is v0.1 (instead of _git).


inherit deploy

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do_configure[noexec] = "1"

do_compile() {
oe_runmake
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need, already covered by base.bbclass.


do_deploy() {
install -d ${DEPLOY_DIR_IMAGE}
install -m 0644 ${S}/qcom-metadata.dtb ${DEPLOY_DIR_IMAGE}/qcom-metadata.dtb
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

${B} instead

}
addtask deploy after do_compile before do_build
Loading