diff --git a/packages/jumpstarter-cli/jumpstarter_cli/j.py b/packages/jumpstarter-cli/jumpstarter_cli/j.py index 29624c230..5f9a8c552 100644 --- a/packages/jumpstarter-cli/jumpstarter_cli/j.py +++ b/packages/jumpstarter-cli/jumpstarter_cli/j.py @@ -8,6 +8,7 @@ from anyio.from_thread import BlockingPortal from jumpstarter_cli_common.exceptions import async_handle_exceptions, leaf_exceptions from jumpstarter_cli_common.signal import signal_handler +from rich import traceback from jumpstarter.utils.env import env_async @@ -43,6 +44,7 @@ async def cli(): def j(): + traceback.install() run(j_async) diff --git a/packages/jumpstarter-driver-flashers/README.md b/packages/jumpstarter-driver-flashers/README.md index c9cbc0de1..6c21cb4a4 100644 --- a/packages/jumpstarter-driver-flashers/README.md +++ b/packages/jumpstarter-driver-flashers/README.md @@ -68,7 +68,9 @@ HTTP servers are used to serve images to the DUT bootloader and busybox shell. | cache_dir | The directory to cache the images | str | no | /var/lib/jumpstarter/flasher | | tftp_dir | The directory to serve the images via TFTP | str | no | /var/lib/tftpboot | | http_dir | The directory to serve the images via HTTP | str | no | /var/www/html | - +| variant | The variant of the DUT DTB to flash to | str | no | (the default defined in the manifest) | +| manifest | The manifest to use from the bundle. Every bundle can have multiple manifests, this is the name of the manifest to use | str | no | manifest.yaml | +| default_target | The default target to flash to if none specified | str | no | | ## BaseFlasher API diff --git a/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/bundle.py b/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/bundle.py index ef124b078..e593a0e4d 100644 --- a/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/bundle.py +++ b/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/bundle.py @@ -1,5 +1,5 @@ import os -from typing import Literal, Optional +from typing import Literal import yaml from pydantic import BaseModel, Field @@ -9,12 +9,14 @@ class FileAddress(BaseModel): file: str address: str - class DtbVariant(BaseModel): + bootcmd: None | str = None + file: None | str = None + +class Dtb(BaseModel): default: str address: str - variants: dict[str, str] - + variants: dict[str, DtbVariant] class FlasherLogin(BaseModel): login_prompt: str @@ -25,15 +27,15 @@ class FlasherLogin(BaseModel): class FlashBundleSpecV1Alpha1(BaseModel): manufacturer: str - link: Optional[str] + link: None | str bootcmd: str shelltype: Literal["busybox"] = Field(default="busybox") login: FlasherLogin = Field(default_factory=lambda: FlasherLogin(login_prompt="login:", prompt="#")) default_target: str targets: dict[str, str] kernel: FileAddress - initram: Optional[FileAddress] = None - dtb: Optional[DtbVariant] = None + initram: None | FileAddress = None + dtb: None | Dtb = None preflash_commands: list[str] = Field(default_factory=list) @@ -56,10 +58,33 @@ def get_dtb_file(self, variant: str | None = None) -> str | None: if not self.spec.dtb: return None + # if no variant is provided, use the default variant name from the manifest if not variant: variant = self.spec.dtb.default - return self.spec.dtb.variants.get(variant) + # look for the variant struct in this manifest + variant_struct = self.spec.dtb.variants.get(variant) + if variant_struct: + return variant_struct.file + else: + raise ValueError(f"DTB variant {variant} not found in the manifest.") + + def get_boot_cmd(self, variant: str | None = None) -> str: + if not self.spec.dtb: + return self.spec.bootcmd + # if no variant is provided, use the default variant name from the manifest + if not variant: + variant = self.spec.dtb.default + # look for the variant struct in this manifest + variant_struct = self.spec.dtb.variants.get(variant) + if variant_struct: + # If variant has a custom bootcmd, use it; otherwise fall back to default + if variant_struct.bootcmd: + return variant_struct.bootcmd + else: + return self.spec.bootcmd + else: + raise ValueError(f"DTB variant {variant} not found in the manifest.") def get_kernel_address(self) -> str: return self.spec.kernel.address diff --git a/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/client.py b/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/client.py index 162052c00..09d47293d 100644 --- a/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/client.py +++ b/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/client.py @@ -117,7 +117,7 @@ def flash( with self._services_up(): with self._busybox() as console: manifest = self.manifest - target = partition or manifest.spec.default_target + target = partition or self.call("get_default_target") or manifest.spec.default_target if not target: raise ArgumentError("No partition or default target specified") @@ -401,19 +401,28 @@ def _busybox(self): if manifest.get_initram_file(): initram_filename = Path(manifest.get_initram_file()).name initram_address = manifest.get_initram_address() - self.uboot.run_command(f"tftpboot {initram_address} {initram_filename}", timeout=120) - - if manifest.get_dtb_file(): - dtb_filename = Path(manifest.get_dtb_file()).name - dtb_address = manifest.get_dtb_address() - self.uboot.run_command(f"tftpboot {dtb_address} {dtb_filename}", timeout=120) + if initram_address: + self.uboot.run_command(f"tftpboot {initram_address} {initram_filename}", timeout=120) + + try: + dtb_file = manifest.get_dtb_file() + if dtb_file: + dtb_filename = Path(dtb_file).name + dtb_address = manifest.get_dtb_address() + if dtb_address: + self.uboot.run_command(f"tftpboot {dtb_address} {dtb_filename}", timeout=120) + except ValueError: + # DTB variant not found, skip DTB loading + pass with self.serial.pexpect() as console: if self._console_debug: console.logfile_read = sys.stdout.buffer - self.logger.info(f"Running boot command: {manifest.spec.bootcmd}") - console.send(manifest.spec.bootcmd + "\n") + bootcmd = self.call("get_bootcmd") + + self.logger.info(f"Running boot command: {bootcmd}") + console.send(bootcmd + "\n") # if manifest has login details, we need to login if manifest.spec.login.username: diff --git a/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver.py b/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver.py index d85814e97..e9fc177bf 100644 --- a/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver.py +++ b/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver.py @@ -17,6 +17,9 @@ class BaseFlasher(Driver): """driver for Jumpstarter""" flasher_bundle: str = field(default="quay.io/jumpstarter-dev/jumpstarter-flasher-test:latest") + variant: None | str = field(default=None) + manifest: str = field(default="manifest.yaml") + default_target: None | str = field(default=None) cache_dir: str = field(default="/var/lib/jumpstarter/flasher") tftp_dir: str = field(default="/var/lib/tftpboot") http_dir: str = field(default="/var/www/html") @@ -56,12 +59,16 @@ def __post_init__(self): # bundles that have already been downloaded in the current session self._downloaded = {} - self._use_dtb = None # use default dtb unless set by client @classmethod def client(cls) -> str: return "jumpstarter_driver_flashers.client.BaseFlasherClient" + @export + async def get_default_target(self): + """Return the default target""" + return self.default_target + @export async def setup_flasher_bundle(self, force_flash_bundle: str | None = None): """Setup flasher bundle @@ -79,13 +86,15 @@ async def setup_flasher_bundle(self, force_flash_bundle: str | None = None): self.logger.info(f"Setting up kernel in tftp: {kernel_path}") await self.tftp.storage.copy_exporter_file(kernel_path, kernel_path.name) - initram_path = await self._get_file_path(manifest.spec.initram.file) if manifest.spec.initram else None - if initram_path: + initram_file = manifest.get_initram_file() + if initram_file: + initram_path = await self._get_file_path(initram_file) self.logger.info(f"Setting up initram in tftp: {initram_path}") await self.tftp.storage.copy_exporter_file(initram_path, initram_path.name) - dtb_path = await self._get_file_path(manifest.get_dtb_file(self._use_dtb)) if manifest.spec.dtb else None - if dtb_path: + dtb_file = manifest.get_dtb_file(self.variant) if manifest.spec.dtb else None + if dtb_file: + dtb_path = await self._get_file_path(dtb_file) self.logger.info(f"Setting up dtb in tftp: {dtb_path}") await self.tftp.storage.copy_exporter_file(dtb_path, dtb_path.name) @@ -98,12 +107,16 @@ def set_dtb(self, handle): async def use_dtb_variant(self, variant): """Provide a different dtb reference from the flasher bundle""" manifest = await self.get_flasher_manifest() - if manifest.get_dtb_file(variant) is None: + # Check if the variant exists in the manifest + if not manifest.spec.dtb or variant not in manifest.spec.dtb.variants: + variant_list = [] + if manifest.spec.dtb: + variant_list = list(manifest.spec.dtb.variants.keys()) raise ValueError( f"DTB variant {variant} not found in the flasher bundle, " - f"available variants are: {list(manifest.spec.dtb.variants.keys())}" + f"available variants are: {variant_list}." ) - self._use_dtb = variant + self.variant = variant def set_kernel(self, handle): """Provide a different kernel from client""" @@ -146,17 +159,19 @@ async def _get_file_path(self, filename) -> Path: This function will ensure that the bundle is downloaded into cache, and then return the path to the requested file in the cache directory. """ + if filename is None: + raise ValueError("filename cannot be None") bundle_dir = await anyio.to_thread.run_sync(self._download_to_cache) return Path(bundle_dir) / filename @export async def get_flasher_manifest_yaml(self) -> str: """Return the manifest yaml as a string for client side consumption""" - with open(await self._get_file_path("manifest.yaml")) as f: + with open(await self._get_file_path(self.manifest)) as f: return f.read() async def get_flasher_manifest(self) -> FlasherBundleManifestV1Alpha1: - filename = await self._get_file_path("manifest.yaml") + filename = await self._get_file_path(self.manifest) return FlasherBundleManifestV1Alpha1.from_file(filename) @export @@ -177,7 +192,11 @@ async def get_initram_filename(self) -> str | None: async def get_dtb_filename(self) -> str: """Return the dtb filename""" manifest = await self.get_flasher_manifest() - return Path(manifest.get_dtb_file(self._use_dtb)).name + dtb_file = manifest.get_dtb_file(self.variant) + if dtb_file: + return Path(dtb_file).name + else: + return "" @export async def get_dtb_address(self) -> str: @@ -197,6 +216,11 @@ async def get_initram_address(self) -> str: manifest = await self.get_flasher_manifest() return manifest.get_initram_address() + @export + async def get_bootcmd(self) -> str: + """Return the bootcmd""" + manifest = await self.get_flasher_manifest() + return manifest.get_boot_cmd(self.variant) @dataclass(kw_only=True) class TIJ784S4Flasher(BaseFlasher): diff --git a/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver_test.py b/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver_test.py index 15d17fa05..aaeae2820 100644 --- a/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver_test.py +++ b/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/driver_test.py @@ -6,6 +6,7 @@ from jumpstarter_driver_pyserial.driver import PySerial from .driver import BaseFlasher +from jumpstarter.client.core import DriverInvalidArgument from jumpstarter.common.exceptions import ConfigurationError from jumpstarter.common.utils import serve @@ -26,6 +27,7 @@ def temp_dirs(): def complete_flasher(temp_dirs): cache, http, tftp = temp_dirs yield BaseFlasher( + flasher_bundle="quay.io/jumpstarter-dev/jumpstarter-flasher-test:new", cache_dir=cache, http_dir=http, tftp_dir=tftp, @@ -35,7 +37,6 @@ def complete_flasher(temp_dirs): }, ) - def test_missing_serial(temp_dirs): cache, http, tftp = temp_dirs with pytest.raises(ConfigurationError): @@ -88,3 +89,55 @@ def test_drivers_flashers_addresses(complete_flasher): assert client.call("get_kernel_address") == "0x82000000" assert client.call("get_initram_address") == "0x83000000" assert client.call("get_dtb_address") == "0x84000000" + + +def test_drivers_flashers_get_bootcmd_default(complete_flasher): + """Test getting the default boot command""" + with serve(complete_flasher) as client: + bootcmd = client.call("get_bootcmd") + assert bootcmd == "booti 0x82000000 - 0x84000000" + + +def test_drivers_flashers_get_bootcmd_with_dtb_variant(complete_flasher): + """Test getting boot command with DTB variant that has custom bootcmd""" + with serve(complete_flasher) as client: + # Switch to variant with custom boot command + client.call("use_dtb_variant", "othercmd") + bootcmd = client.call("get_bootcmd") + assert bootcmd == "bootm" + + +def test_drivers_flashers_get_bootcmd_with_dtb_variant_no_custom_cmd(complete_flasher): + """Test getting boot command with DTB variant that has no custom bootcmd (should use default)""" + with serve(complete_flasher) as client: + # Switch to variant without custom boot command + client.call("use_dtb_variant", "alternate") + bootcmd = client.call("get_bootcmd") + assert bootcmd == "booti 0x82000000 - 0x84000000" + + +def test_drivers_flashers_get_bootcmd_variant_switching(complete_flasher): + """Test that boot command changes when switching between DTB variants""" + with serve(complete_flasher) as client: + # Start with default variant + bootcmd = client.call("get_bootcmd") + assert bootcmd == "booti 0x82000000 - 0x84000000" + + # Switch to variant with custom boot command + client.call("use_dtb_variant", "othercmd") + bootcmd = client.call("get_bootcmd") + assert bootcmd == "bootm" + + # Switch back to default variant + client.call("use_dtb_variant", "test-dtb") + bootcmd = client.call("get_bootcmd") + assert bootcmd == "booti 0x82000000 - 0x84000000" + + +def test_drivers_flashers_get_bootcmd_invalid_variant(complete_flasher): + """Test that get_bootcmd raises DriverInvalidArgument for invalid DTB variant""" + with serve(complete_flasher) as client: + # Set an invalid variant + with pytest.raises(DriverInvalidArgument): + client.call("use_dtb_variant", "noexists") + diff --git a/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/test_bundle.py b/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/test_bundle.py index 05e9d5a4f..6f145eade 100644 --- a/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/test_bundle.py +++ b/packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/test_bundle.py @@ -1,5 +1,7 @@ from pathlib import Path +import pytest + from . import bundle @@ -13,3 +15,40 @@ def test_bundle_read(): "usd": "/sys/class/block#4fb0000", "emmc": "/sys/class/block#4f80000", } + + +def test_bundle_get_boot_cmd_default(): + """Test getting default boot command from test bundle""" + manifest_file = Path(__file__).parent / "../oci_bundles/test/manifest.yaml" + flasher_bundle = bundle.FlasherBundleManifestV1Alpha1.from_file(manifest_file) + + # Test default boot command (no variant specified) + bootcmd = flasher_bundle.get_boot_cmd() + assert bootcmd == "booti 0x82000000 - 0x84000000" + + +def test_bundle_get_boot_cmd_with_variant(): + """Test getting boot command with specific DTB variant""" + manifest_file = Path(__file__).parent / "../oci_bundles/test/manifest.yaml" + flasher_bundle = bundle.FlasherBundleManifestV1Alpha1.from_file(manifest_file) + + # Test variant with custom boot command + bootcmd = flasher_bundle.get_boot_cmd("othercmd") + assert bootcmd == "bootm" + + # Test variant without custom boot command (should use default) + bootcmd = flasher_bundle.get_boot_cmd("alternate") + assert bootcmd == "booti 0x82000000 - 0x84000000" + + # Test default variant explicitly + bootcmd = flasher_bundle.get_boot_cmd("test-dtb") + assert bootcmd == "booti 0x82000000 - 0x84000000" + + +def test_bundle_get_boot_cmd_invalid_variant(): + """Test that get_boot_cmd raises ValueError for invalid variant""" + manifest_file = Path(__file__).parent / "../oci_bundles/test/manifest.yaml" + flasher_bundle = bundle.FlasherBundleManifestV1Alpha1.from_file(manifest_file) + + with pytest.raises(ValueError, match="DTB variant noexists not found in the manifest"): + flasher_bundle.get_boot_cmd("noexists") diff --git a/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/automotive.its b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/automotive.its new file mode 100644 index 000000000..838103627 --- /dev/null +++ b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/automotive.its @@ -0,0 +1,78 @@ +/dts-v1/; + +/ { + description = "kernel-automotive flasher FIT Image"; + #address-cells = <1>; + + images { + kernel { + description = "kernel-automotive"; + data = /incbin/("/kernel-automotive/vmlinuz"); + type = "kernel"; + arch = "arm64"; + os = "linux"; + compression = "none"; + load = <0x48080000>; + entry = <0x48080000>; + hash { + algo = "sha256"; + }; + }; + fdt-spider { + description = "DTB Renesas 8779f0-spider"; + data = /incbin/("/kernel-automotive/dtb/renesas/r8a779f0-spider.dtb"); + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + load = <0x48000000>; + entry = <0x48000000>; + hash { + algo = "sha256"; + }; + }; + fdt-s4sk { + description = "DTB Renesas r8a779f4-s4sk"; + data = /incbin/("/kernel-automotive/dtb/renesas/r8a779f4-s4sk.dtb"); + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + load = <0x48000000>; + entry = <0x48000000>; + hash { + algo = "sha256"; + }; + }; + initrd { + description = "Initrd"; + data = /incbin/("/buildroot/output/images/rootfs.cpio.lzo"); + type = "ramdisk"; + arch = "arm64"; + os = "linux"; + hash { + algo = "sha256"; + }; + }; + }; + + configurations { + default = "spider"; + spider { + description = "Boot Renesas R-Car S4 Spider"; + kernel = "kernel"; + fdt = "fdt-spider"; + ramdisk = "initrd"; + hash { + algo = "sha256"; + }; + }; + s4sk { + description = "Boot Renesas R-Car S4 SK"; + kernel = "kernel"; + fdt = "fdt-s4sk"; + ramdisk = "initrd"; + hash { + algo = "sha256"; + }; + }; + }; +}; diff --git a/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/build_fits.sh b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/build_fits.sh new file mode 100755 index 000000000..1a2c5d64a --- /dev/null +++ b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/build_fits.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -euo pipefail + +dnf install --setopt=install_weak_deps=false -y git make gcc gcc-c++ which file diffutils wget cpio rsync bc lzop zip patch perl tar qemu-system-aarch64 qemu-img unzboot uboot-tools kmod awk + +git clone --depth 1 --branch 2025.05 https://github.com/buildroot/buildroot /buildroot + +# build default buildroot kernel & initramfs +cp buildroot_defconfig /buildroot/configs/ +cp -R overlay /buildroot +( cd /buildroot; make buildroot_defconfig && make ) +mkimage -f buildroot.its data/flasher-buildroot.itb +rm -rf /buildroot/overlay + +# replace kernel with kernel-automotive and rebuild +cp -R overlay /buildroot +./replace_kernel.sh /buildroot/overlay +( cd /buildroot && make ) +mkimage -f automotive.its data/flasher-automotive.itb +rm -rf /buildroot/overlay diff --git a/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/buildroot.its b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/buildroot.its new file mode 100644 index 000000000..504074ccc --- /dev/null +++ b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/buildroot.its @@ -0,0 +1,77 @@ +/dts-v1/; + +/ { + description = "buildroot kernel flasher FIT Image"; + #address-cells = <1>; + + images { + kernel { + description = "buildroot Kernel"; + data = /incbin/("/buildroot/output/images/Image"); + type = "kernel"; + arch = "arm64"; + os = "linux"; + compression = "none"; + load = <0x80000000>; + entry = <0x80000000>; + hash { + algo = "sha256"; + }; + }; + initrd { + description = "Initrd"; + data = /incbin/("/buildroot/output/images/rootfs.cpio.lzo"); + type = "ramdisk"; + arch = "arm64"; + os = "linux"; + compression = "none"; + hash { + algo = "sha256"; + }; + }; + fdt-j784s4 { + description = "DTB TI J784S4EVM"; + data = /incbin/("/buildroot/output/images/k3-j784s4-evm.dtb"); + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + load = <0x88000000>; + hash { + algo = "sha256"; + }; + }; + fdt-am69 { + description = "DTB TI SK-AM69"; + data = /incbin/("/buildroot/output/images/k3-am69-sk.dtb"); + type = "flat_dt"; + arch = "arm64"; + compression = "none"; + load = <0x88000000>; + hash { + algo = "sha256"; + }; + }; + }; + + configurations { + default = "j784s4"; + j784s4 { + description = "Boot TI J784S4EVM"; + kernel = "kernel"; + fdt = "fdt-j784s4"; + ramdisk = "initrd"; + hash { + algo = "sha256"; + }; + }; + am69 { + description = "Boot TI SK-AM69"; + kernel = "kernel"; + fdt = "fdt-am69"; + ramdisk = "initrd"; + hash { + algo = "sha256"; + }; + }; + }; +}; diff --git a/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/buildroot_defconfig b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/buildroot_defconfig new file mode 100644 index 000000000..2c7843886 --- /dev/null +++ b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/buildroot_defconfig @@ -0,0 +1,33 @@ +# Initrd config +BR2_aarch64=y +BR2_TOOLCHAIN_EXTERNAL=y +BR2_TARGET_GENERIC_HOSTNAME="flasher" +BR2_TARGET_GENERIC_ISSUE="flasher" +BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y +BR2_TARGET_GENERIC_ROOT_PASSWD="" +BR2_SYSTEM_DHCP="eth0" +BR2_ROOTFS_OVERLAY="$(CONFIG_DIR)/overlay" +BR2_PACKAGE_CA_CERTIFICATES=y +BR2_PACKAGE_OPENSSL=y +BR2_PACKAGE_LIBCURL=y +BR2_PACKAGE_LIBCURL_CURL=y +BR2_PACKAGE_NTP=y +BR2_PACKAGE_NTP_SNTP=y +BR2_PACKAGE_NTP_NTPDATE=y +BR2_TARGET_ROOTFS_CPIO=y +BR2_TARGET_ROOTFS_CPIO_LZO=y +BR2_PACKAGE_DROPBEAR=n +# BR2_TARGET_ROOTFS_TAR is not set +# +# +# Buildroot Kernel config +# include initramfs within the kernel Image +# on J784S4 the size exceeds uboot's CONFIG_SYS_BOOTM_LEN +# BR2_TARGET_ROOTFS_INITRAMFS=y +BR2_LINUX_KERNEL=y +BR2_LINUX_KERNEL_USE_ARCH_DEFAULT_CONFIG=y +BR2_LINUX_KERNEL_LZO=y +BR2_LINUX_KERNEL_IMAGE=y +BR2_LINUX_KERNEL_DTS_SUPPORT=y +BR2_LINUX_KERNEL_INTREE_DTS_NAME="ti/k3-j784s4-evm ti/k3-am69-sk" + diff --git a/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/data/.gitkeep b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/data/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/manifest-renesas.yaml b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/manifest-renesas.yaml new file mode 100644 index 000000000..e38cbc6e6 --- /dev/null +++ b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/manifest-renesas.yaml @@ -0,0 +1,30 @@ +apiVersion: jumpstarter.dev/v1alpha1 +kind: FlashBundleManifest +metadata: + name: rcar-s4 +spec: + manufacturer: Renesas + link: "https://www.renesas.com/en/products/automotive-products/automotive-system-chips-socs/r-car-s4-automotive-system-chip-soc-car-servercommunication-gateway" + # boot default configuration R-Car S4 Spider, for S4SK use "bootm 0x58000000#s4sk" + bootcmd: "bootm 0x58000000" + shelltype: "busybox" + login: + login_prompt: "login:" + username: "root" + prompt: "#" + default_target: "emmc" + targets: + emmc: "/dev/mmcblk0" + kernel: + file: data/flasher-automotive.itb + address: "0x58000000" + dtb: + default: spider + address: "0x48000000" + variants: + spider: + bootcmd: "bootm 0x58000000#spider" + s4sk: + bootcmd: "bootm 0x58000000#s4sk" + custom: + bootcmd: "bootm 0x58000000:kernel 0x58000000:initrd 0x48000000" diff --git a/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/manifest-ti.yaml b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/manifest-ti.yaml new file mode 100644 index 000000000..edec8ca78 --- /dev/null +++ b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/manifest-ti.yaml @@ -0,0 +1,48 @@ +apiVersion: jumpstarter.dev/v1alpha1 +kind: FlashBundleManifest +metadata: + name: ti-j784s4 +spec: + manufacturer: Texas Instruments + link: "https://www.ti.com/tool/PROCESSOR-SDK-J784S4" +# boot using the default configuration built-in flasher.itb, j784s4 +# you can boot included alternative configurations, e.g. for SK-AM69 use "bootm 0x90000000#am69" + bootcmd: "bootm 0x90000000" + shelltype: "busybox" + login: + login_prompt: "login:" + username: "root" + prompt: "#" + default_target: "usd" + targets: + usd: "/sys/class/block#4fb0000" + emmc: "/sys/class/block#4f80000" +# removed for now, even if it's our documented procedure, if +# the board is configured to boot from sd or emmc (and not SPI), and +# the flashing of the final image fails, it will result in an un-bootable +# system -> lab admin going to the site and re-flashing SD, this can +# only be avoided by using something like sdwire +# +# preflash_commands: +# - "dd if=/dev/zero of=/dev/mmcblk0 bs=512 count=34" +# - "dd if=/dev/zero of=/dev/mmcblk1 bs=512 count=34" +# +# supply custom DTB by loading your own re-using the included kernel and initrd by e.g: +# bootcmd: "bootm 0x90000000:kernel 0x90000000:initrd 0x88000000" +# dtb: +# file: my.dtb +# address: "0x88000000" + kernel: + file: data/flasher-buildroot.itb + address: "0x90000000" + + dtb: + default: j784s4 + address: "0x88000000" + variants: + j784s4: + bootcmd: "bootm 0x90000000#j784s4" + am69: + bootcmd: "bootm 0x90000000#am69" + custom: + bootcmd: "bootm 0x90000000:kernel 0x90000000:initrd 0x88000000" diff --git a/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/manifest.yaml b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/manifest.yaml new file mode 120000 index 000000000..d8d479014 --- /dev/null +++ b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/manifest.yaml @@ -0,0 +1 @@ +manifest-ti.yaml \ No newline at end of file diff --git a/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/overlay/etc/network/if-pre-up.d/wait-carrier.sh b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/overlay/etc/network/if-pre-up.d/wait-carrier.sh new file mode 100755 index 000000000..7afc9a34a --- /dev/null +++ b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/overlay/etc/network/if-pre-up.d/wait-carrier.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +IF_WAIT_DELAY=30 + +if [ "${IFACE}" != "lo" ]; then + ip link set ${IFACE} up + printf "Waiting for interface %s carrier" "${IFACE}" + while [ ${IF_WAIT_DELAY} -gt 0 ]; do + if [ "$(cat /sys/class/net/${IFACE}/carrier)" = "1" ]; then + printf "\n" + exit 0 + fi + sleep 1 + printf "." + : $((IF_WAIT_DELAY -= 1)) + done + printf " timeout!\n" + exit 1 +fi diff --git a/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/overlay/etc/udev/rules.d/10-rename-tsn0.rules b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/overlay/etc/udev/rules.d/10-rename-tsn0.rules new file mode 100644 index 000000000..e3fd0b5f1 --- /dev/null +++ b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/overlay/etc/udev/rules.d/10-rename-tsn0.rules @@ -0,0 +1,2 @@ +# rename Renesas S4 main interface tsn0 to eth0 to unify setup +SUBSYSTEM=="net", ACTION=="add", KERNEL=="tsn0", NAME="eth0" diff --git a/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/replace_kernel.sh b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/replace_kernel.sh new file mode 100755 index 000000000..373e57956 --- /dev/null +++ b/packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/replace_kernel.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +KVER="5.14.0-594.543.el9iv.aarch64" +KMOD=( + # R-Car S4 storage + fixed + renesas_sdhi_internal_dmac + mmc_block + # R-Car S4 networking + gpio-rcar + r8a779f0-ether-serdes + marvell10g + rswitch +) + +[ $# -ne 1 ] && { echo "$0 [target_overlay_dir]"; exit 1; } +ODIR=$1 +mkdir -p /kernel-automotive +pushd /kernel-automotive + +url="https://cbs.centos.org/kojifiles/packages/kernel-automotive" +url="$url/$(echo $KVER | sed -r 's|-|/|; s|\.([^.]*)$|/\1|')" +pkgs=( + kernel-automotive-core-$KVER.rpm + kernel-automotive-modules-$KVER.rpm + kernel-automotive-modules-core-$KVER.rpm +) + + +# fetch kernel rpm packages +for pkg in "${pkgs[@]}"; do + [[ -f $pkg ]] || wget "$url/$pkg" || exit 1 +done + +# extract kernel rpm packages +for pkg in "${pkgs[@]}"; do + echo -n "extracting $pkg ... " + rpm2cpio $pkg | cpio -id +done +echo "extracting kernel ..." +unzboot lib/modules/$KVER/vmlinuz vmlinuz +ln -sfn lib/modules/$KVER/dtb dtb +echo "updating module deps ..." +depmod --errsyms --filesyms lib/modules/$KVER/System.map --basedir $PWD $KVER +echo "building required modules list ..." +for mod in ${KMOD[@]}; do + modprobe -d $PWD -S $KVER --show-depends $mod +done | sed "s|$PWD||; s|^builtin|# builtin|; s|\\.ko\\.zst|.ko|" > modlist + +popd + +echo "installing modules into overlay dir ..." +mkdir -p $ODIR/lib/modules $ODIR/etc/init.d || exit 1 +sed -nr 's|^insmod ||p' < /kernel-automotive/modlist | while read mod; do + mkdir -p "$ODIR$(dirname $mod)" + zstd -d "/kernel-automotive$mod.zst" -o "$ODIR$mod" +done + +echo "adding modules start-up script to overlay ..." +script=$ODIR/etc/init.d/S01modules +cat >$script <