diff --git a/classes/l4re.yaml b/classes/l4re.yaml index 65a11601..c88dd10a 100644 --- a/classes/l4re.yaml +++ b/classes/l4re.yaml @@ -40,6 +40,14 @@ # packageScript: | # l4reInstall $1 \ # bootstrap.uimage +# +# To assemble the image in a separate recipe with l4image (see l4re::dist), +# install everything the image needs instead: +# +# packageScript: | +# l4reInstallDist $1 +# +# Dependencies using the tools of such a package get the l4image tool. inherit: [pkg-config, make] @@ -78,6 +86,11 @@ buildSetup: | makeParallel -C $1 O=$BOB_CWD/build \ ${3:-} + + # l4reInstallDist has no access to the source dir + mkdir -p $BOB_CWD/tool/bin $BOB_CWD/tool/lib + cp $1/tool/bin/l4image $BOB_CWD/tool/bin/ + rsync -a --delete $1/tool/lib/L4 $BOB_CWD/tool/lib/ } # $1: source dir @@ -103,3 +116,35 @@ packageSetup: | cp -L "$1/build/images/$i" . done } + + # Install the parts of the build dir that l4image takes the modules from + # (see the search path of l4reDistImage in l4re::dist) and the l4image + # tool. + # + # $1: build dir + l4reInstallDist() + { + rsync -a --copy-unsafe-links \ + --include="/assets/***" \ + --include="/bin/" \ + --exclude="/bin/host/" \ + --exclude="/bin/targetsys/" \ + --include="/bin/*/" \ + --include="/bin/*/l4f/***" \ + --include="/bin/*/plain/***" \ + --include="/lib/" \ + --exclude="/lib/host/" \ + --include="/lib/*/" \ + --include="/lib/*/std/" \ + --include="/lib/*/std/l4f/" \ + --include="/lib/*/std/l4f/*.so*" \ + --exclude="*" \ + "$1/build/" . + + rsync -a "$1/tool" . + } + +provideTools: + l4image: + path: tool/bin + dependTools: [perl] diff --git a/classes/l4re/dist.yaml b/classes/l4re/dist.yaml new file mode 100644 index 00000000..c73cd64e --- /dev/null +++ b/classes/l4re/dist.yaml @@ -0,0 +1,264 @@ +# Assemble a bootable L4Re image out of an already built l4re package. +# +# This runs l4image directly instead of the l4re build system. The l4re +# package must be installed with l4reInstallDist of the l4re class, which also +# provides the l4image tool. Use it like this in your own recipes: +# +# inherit: [l4re::dist] +# +# depends: +# # add additional dependencies here, like linux kernels or external +# # device trees +# - fiasco +# # the actual l4re build +# - name: l4re-build +# use: [result, deps, tools] +# - ... +# +# buildScript: | +# l4reDistImage ${BOB_DEP_PATHS[l4re-build]} \ +# raw rpi test test.list "" "${@:2}" +# +# packageScript: | +# l4reDistInstall $1 +# +# The uimage and itb images are loaded to the address the l4re image was +# linked for. Set L4RE_IMAGE_LOAD_ADDRESS if the target needs a different +# one. + +depends: + - tools: + target-toolchain: host-compat-toolchain + depends: + - name: bsp::uboot-tools + use: [tools] + - name: devel::dtc + use: [tools] + - name: utils::mtools + use: [tools] + +buildTools: [l4image, uboot-tools, dtc, mtools] +buildVars: [L4RE_IMAGE_COMPRESSION] +buildSetup: | + # Write the image tree source of the FIT image. + # + # $1: device tree, may be empty + # $2: load address + l4reMkimageIts() + { + local dtb="$1" loadaddr="$2" name="L4Re Image" + + loadaddr=$(printf "0x%x 0x%x" $((loadaddr >> 32)) \ + $((loadaddr & 0xffffffff))) + + # /incbin/ resolves relative to the source file + case "$dtb" in + ""|/*) ;; + *) dtb="$PWD/$dtb" ;; + esac + + if [ -n "$dtb" ] ; then + name="${dtb##*/}" + name="${name%.*}" + fi + + cat <; + + images { + kernel-1 { + description = "L4Re Image"; + data = /incbin/("$PWD/images/bootstrap.raw"); + type = "kernel"; + arch = "$ARCH"; + os = "linux"; + compression = "${L4RE_IMAGE_COMPRESSION:-none}"; + load = <$loadaddr>; + entry = <$loadaddr>; + hash-1 { + algo = "crc32"; + }; + }; + EOF + + if [ -n "$dtb" ] ; then + cat < images/bootstrap.its + + # Store the sub-images outside the FIT structure (-E) and align + # them to 8 bytes (-B). Embedded data is only 4 byte aligned, + # which violates the 8 byte alignment the device tree spec + # requires for the DTB. A boot loader passing the DTB in place + # then hands over a misaligned blob. + mkimage -f images/bootstrap.its -E -B 8 images/bootstrap.itb + + rm images/bootstrap.its + else + # the uimage header holds 32 bit addresses only + if [ $((loadaddr > 0xffffffff)) = 1 ] ; then + >&2 echo "load address '$loadaddr' does not fit into a uimage" + return 1 + fi + + mkimage \ + -a "$loadaddr" \ + -e "$loadaddr" \ + -A "$ARCH" \ + -C "${L4RE_IMAGE_COMPRESSION:-none}" \ + -n "L4Re Image" \ + -d images/bootstrap.raw \ + "images/bootstrap.$1" + fi + + rm images/bootstrap.raw + } + + # Put the EFI application on a FAT disk, where the firmware looks for it. + l4reEfiDisk() + { + local name size + + case "$ARCH" in + amd64) name=bootx64.efi ;; + x86) name=bootia32.efi ;; + arm64) name=bootaa64.efi ;; + *) + >&2 echo "no efi boot file name for '$ARCH'" + return 1 + ;; + esac + + # the file system needs some head room on top of the image + size=$(( $(du -k images/bootstrap.efi | cut -f 1) * 12 / 10 )) + + dd if=/dev/zero of=images/bootstrap.efi.img bs=1K count=$size + mformat -i images/bootstrap.efi.img :: + mmd -i images/bootstrap.efi.img ::/EFI ::/EFI/BOOT + mcopy -i images/bootstrap.efi.img images/bootstrap.efi "::/EFI/BOOT/$name" + } + + # The search path matches what l4reInstallDist installs. + # + # $1: path of the package with the l4re build + # $2: image type: elf, raw, efi, uimage or itb + # $3: platform type + # $4: modules entry + # $5: modules list + # $6: device tree for the itb image, empty for none + # $7+: search paths for the modules, searched before the l4re build + l4reDistImage() + { + local l4re="$1" type="$2" platform="$3" entry="$4" modlist="$5" \ + itbdtb="$6" + shift 6 + + local sys d + for d in "$l4re"/bin/*/l4f ; do + sys="${d%/l4f}" + sys="${sys##*/}" + done + + # l4image evaluates the modules list, which selects modules by these + export PLATFORM_TYPE="$platform" + export ARCH="${sys%%_*}" + export CPU="${sys#*_}" + case "$ARCH" in + *64) export BITS=64 ;; + *) export BITS=32 ;; + esac + + # uimage and itb are a raw image wrapped by mkimage + local base="$type" + case "$type" in + elf|raw|efi) ;; + uimage|itb) base=raw ;; + *) + >&2 echo "unknown image type '$type'" + return 1 + ;; + esac + + local -a sp=( + "$@" + "$l4re"/assets + "$l4re"/bin/$sys/l4f + "$l4re"/bin/$sys/plain + "$l4re"/lib/$sys/std/l4f + ) + + if [ ! -e "$l4re/bin/$sys/plain/bootstrap.$base" ] ; then + >&2 echo "l4re has no $base base image, its config does not build one" + return 1 + fi + + mkdir -p images + l4image -i "$l4re/bin/$sys/plain/bootstrap.$base" \ + -o "images/bootstrap.$base" --verbose create \ + --entry "$entry" \ + --modules-list-file "$modlist" \ + --search-path "${sp[*]}" + + case "$type" in + uimage|itb) l4reMkimage "$type" "$itbdtb" ;; + efi) l4reEfiDisk ;; + esac + } + +packageSetup: | + _L4RE_BUILD_PATH="$1" + + # $1: build dir (optional) + l4reDistInstall() + { + cp "${1:-$_L4RE_BUILD_PATH}"/images/* . + }