<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Raghu Bharadwaj</title>
    <description>The latest articles on DEV Community by Raghu Bharadwaj (@raghu_bharadwaj_404e60eb0c).</description>
    <link>https://dev.to/raghu_bharadwaj_404e60eb0c</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1782496%2Ff6a2f0b0-5d25-4cfc-99b7-83f5e8326288.jpg</url>
      <title>DEV Community: Raghu Bharadwaj</title>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raghu_bharadwaj_404e60eb0c"/>
    <language>en</language>
    <item>
      <title>Kernel &amp; Embedded News: Linux 7.2 Final RC; FFmpeg 9.0 Released</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Tue, 11 Aug 2026 06:05:03 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/kernel-embedded-news-linux-72-final-rc-ffmpeg-90-released-3i4f</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/kernel-embedded-news-linux-72-final-rc-ffmpeg-90-released-3i4f</guid>
      <description>&lt;p&gt;Linux 7.2 has reached its final planned release candidate, and Linus Torvalds expects the stable release on 16 August; he now describes the volume of late fixes, many produced by AI review tools, as the new normal. FFmpeg 9.0 shipped on 4 August with an ABI break across all seven libraries and TLS certificate verification enabled by default. In the kernel, a missed check left two legacy PCI sysfs files writable under lockdown since 2019, and the removal of Qualcomm's QCE crypto driver has been proposed after benchmarks showed it far slower than the CPU. In embedded hardware, Espressif's ESP32-S31 entered mass production and Radxa announced two Qualcomm-based system-on-modules.&lt;/p&gt;

&lt;p&gt;Two themes connect this edition: a release process adjusting to the fix volume that AI review tools generate, and the value of measuring what you assume — a lockdown mode that did not lock everything, and a crypto accelerator measured slower than the CPU it serves. Alongside them sit a major userspace release and two hardware announcements at different layers of an embedded product.&lt;/p&gt;

&lt;h2&gt;
  
  
  In this edition
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linux 7.2-rc7 is the final planned release candidate.&lt;/strong&gt; Torvalds released &lt;a href="https://lore.kernel.org/lkml/CAHk-=wiDq_aaSkBgTN=SGpa5bfTsRGvwhg8sJcFyWgPFf4x0HA@mail.gmail.com/T/#u" rel="noopener noreferrer"&gt;7.2-rc7&lt;/a&gt; on 9 August and expects the stable kernel on 16 August, calling the AI-driven fix volume "the new normal".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FFmpeg 9.0 "Lei" is released.&lt;/strong&gt; The &lt;a href="https://code.ffmpeg.org/FFmpeg/FFmpeg/src/branch/release/9.0/Changelog" rel="noopener noreferrer"&gt;4 August release&lt;/a&gt; bumps the major version of all seven libraries, rewrites swscale, decodes animated WebP, and turns on TLS certificate verification by default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kernel lockdown left legacy PCI files open since 2019.&lt;/strong&gt; A &lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git/commit/?h=next&amp;amp;id=747b9bbbbdfdee51aee2456388f9b94b5086de4d" rel="noopener noreferrer"&gt;queued PCI fix&lt;/a&gt; adds the missing lockdown checks to the &lt;code&gt;legacy_io&lt;/code&gt; and &lt;code&gt;legacy_mem&lt;/code&gt; sysfs handlers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Removal of Qualcomm's QCE crypto driver is proposed.&lt;/strong&gt; Eric Biggers &lt;a href="https://lore.kernel.org/lkml/20260724050645.223799-1-ebiggers@kernel.org/" rel="noopener noreferrer"&gt;posted a patch&lt;/a&gt; to delete the driver after measuring it far slower than the ARMv8 Crypto Extensions; the discussion is ongoing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESP32-S31 enters mass production.&lt;/strong&gt; Espressif's &lt;a href="https://www.espressif.com/en/news/ESP32_S31_Mass_Production" rel="noopener noreferrer"&gt;dual-core RISC-V SoC&lt;/a&gt; combines Wi-Fi 6, Bluetooth 5.4 with Classic and LE Audio, 802.15.4 and a Gigabit Ethernet MAC in one chip.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Radxa reveals two Qualcomm-based system-on-modules.&lt;/strong&gt; The &lt;a href="https://linuxgizmos.com/radxa-broadens-rcore-series-with-qualcomm-based-ai-soms/" rel="noopener noreferrer"&gt;rCore-Q8280 and rCore-Q6490&lt;/a&gt; pair a Snapdragon 8cx Gen 3 and a Dragonwing QCS6490 with very different product-availability commitments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Linux 7.2 closes with a large final RC, and Torvalds calls it the new normal
&lt;/h2&gt;

&lt;p&gt;Linus Torvalds released &lt;a href="https://lore.kernel.org/lkml/CAHk-=wiDq_aaSkBgTN=SGpa5bfTsRGvwhg8sJcFyWgPFf4x0HA@mail.gmail.com/T/#u" rel="noopener noreferrer"&gt;Linux 7.2-rc7&lt;/a&gt; on Sunday, 9 August. By the seventh release candidate a development cycle has usually gone quiet. This one has not, and Torvalds was direct about the reason:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I can't say that I'm exactly thrilled about the size of this all, but it is what it is: the new normal with a lot of fixes, many of them due to review by various AI tools."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He added that nothing in the RC looks particularly worrying — it is small fixes spread across drivers, filesystems, networking and architecture code, with s390 crypto, Btrfs and netfilter ipset standing out in the diffstat. He sees no value in delaying the release, so 7.2 stable is expected on 16 August unless a serious problem appears and forces an rc8.&lt;/p&gt;

&lt;p&gt;The memory-management side closed a race condition that could produce a use-after-free and had been in the kernel for around eight years. Btrfs brought back its fixup worker infrastructure to deal with a silent data-loss case. The hardware-monitoring subsystem took a batch of fixes its maintainer described as mostly critical or high severity, many of them for defects the hwmon maintainer credits to the Sashiko AI review bot.&lt;/p&gt;

&lt;p&gt;The practical shift is not the release date; it is that AI review has permanently raised the fix density of every late RC and every stable point release that follows. Downstream kernels will carry more patches per update, and the burden of deciding what matters moves further onto the teams consuming them.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it means for teams planning on 7.2
&lt;/h3&gt;

&lt;p&gt;If your next BSP or distribution baseline targets 7.2 — Ubuntu 26.10 is expected to ship it as the default kernel — put rc7 on your target hardware this week rather than waiting for the tag. The delta from rc7 to final is normally small, so problems found now can still be reported as release blockers. Teams using Btrfs on embedded storage should read the fixup-worker change specifically, since silent data loss is the failure mode that never shows up in a quick test. Expect the 7.2.y stable series to move fast in its first weeks, and budget regression-test time for point releases accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  FFmpeg 9.0 is released: an ABI break and new defaults that affect devices
&lt;/h2&gt;

&lt;p&gt;FFmpeg 9.0 "Lei" was &lt;a href="https://code.ffmpeg.org/FFmpeg/FFmpeg/src/branch/release/9.0/Changelog" rel="noopener noreferrer"&gt;released on 4 August&lt;/a&gt;, about four and a half months after 8.1, carrying more than 2,200 commits from over 160 authors. It bumps the major version of all seven libraries — libavutil 61, libavcodec 63, libavformat 63, libavdevice 63, libavfilter 12, libswscale 10, libswresample 7 — which means an ABI break across the board. Jean-Baptiste Kempf's &lt;a href="https://jbkempf.com/blog/2026/ffmpeg-9.0/" rel="noopener noreferrer"&gt;release write-up&lt;/a&gt; is the best single overview.&lt;/p&gt;

&lt;p&gt;The largest engineering effort is the multi-year rewrite of swscale: conversions are now decomposed into operation lists compiled by C, x86 SIMD, AArch64 NEON or Vulkan SPIR-V backends, though the new paths stay behind &lt;code&gt;SWS_UNSTABLE&lt;/code&gt; for now. Elsewhere, FFmpeg finally decodes animated WebP (a ticket open since 2015), and the AAC decoder handles the 960-sample frames used by DAB+ digital radio. A large body of NEON work speeds up software conversion on Arm boards, and the DNN filters gain an ONNX Runtime backend for running inference inside a filter graph.&lt;/p&gt;

&lt;p&gt;For device teams, the removals and default changes matter more than the features. TLS peer certificates are now verified by default, so a product that pulls streams or updates from an endpoint with a self-signed or expired certificate will start failing after the upgrade. The OpenMAX encoders are gone, which removes the last supported path for old OMX-based encode pipelines. On the command line, &lt;code&gt;-vsync&lt;/code&gt; is removed in favour of &lt;code&gt;-fps_mode&lt;/code&gt;, and NVENC drops SDKs older than 11.1.&lt;/p&gt;

&lt;h3&gt;
  
  
  What to check before you upgrade
&lt;/h3&gt;

&lt;p&gt;Plan the 9.0 upgrade as a porting exercise, not a version bump. Every application linking the libav* libraries needs a rebuild against seven new sonames, so coordinate the migration with your distribution or Yocto layer rather than upgrading one recipe in isolation. Search startup scripts for removed CLI flags, and test every TLS endpoint your product contacts against the new verification default — the correct response to a failure is fixing the certificate, not disabling verification. Pipelines still using OMX encoders should schedule the move to V4L2 M2M or vendor plugins now.&lt;/p&gt;

&lt;h2&gt;
  
  
  A lockdown gap: legacy PCI sysfs files stayed writable since 2019
&lt;/h2&gt;

&lt;p&gt;Kernel lockdown mode restricts what root can do to a running kernel — no writes to &lt;code&gt;/dev/mem&lt;/code&gt;, no direct PCI BAR access, and so on. It is commonly enabled together with UEFI Secure Boot, and many product security arguments lean on it: even if an attacker gains root, the kernel itself stays out of reach.&lt;/p&gt;

&lt;p&gt;It turns out two interfaces were missed. The &lt;code&gt;legacy_io&lt;/code&gt; and &lt;code&gt;legacy_mem&lt;/code&gt; sysfs files, which give access to legacy port I/O and legacy PCI memory space, never received lockdown checks. Krzysztof Wilczyński explains it plainly in the &lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git/commit/?h=next&amp;amp;id=747b9bbbbdfdee51aee2456388f9b94b5086de4d" rel="noopener noreferrer"&gt;fix now queued in the PCI subsystem's next branch&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"As a result, root can still write arbitrary I/O ports and map the legacy I/O and memory spaces while the kernel is locked down, which is the same capability the lockdown is meant to remove."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The checks were added elsewhere in 2019 by commit &lt;code&gt;eb627e17727e&lt;/code&gt; ("PCI: Lock down BAR access when the kernel is locked down"), covering config-space writes, resource mmap and resource I/O writes — but not the legacy handlers. The new patch adds the missing &lt;code&gt;security_locked_down(LOCKDOWN_PCI_ACCESS)&lt;/code&gt; checks, targets the 7.3 merge window, and is marked as a fix for the 2019 commit, so backports into stable series are the likely next step.&lt;/p&gt;

&lt;p&gt;The instructive part is how the gap survived for seven years. Lockdown is not a single global switch; it is a collection of per-interface checks, and every interface that can reach kernel memory has to opt in individually. A new or overlooked interface fails open, not closed. Security audits should therefore test observed behaviour on the shipped kernel instead of trusting the feature description.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to check your device
&lt;/h3&gt;

&lt;p&gt;First confirm what lockdown state your product actually runs in — the bracketed entry is the active mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /sys/kernel/security/lockdown
none &lt;span class="o"&gt;[&lt;/span&gt;integrity] confidentiality
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your threat model counts on lockdown to keep root away from the running kernel, add this patch to your tracking list and pick it up when it reaches your stable series; it is a small, self-contained backport. Where the platform exposes the legacy PCI files, a direct write attempt under lockdown makes a useful acceptance test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qualcomm's QCE crypto driver faces removal for being slower than the CPU
&lt;/h2&gt;

&lt;p&gt;In late July, kernel crypto maintainer Eric Biggers &lt;a href="https://lore.kernel.org/lkml/20260724050645.223799-1-ebiggers@kernel.org/" rel="noopener noreferrer"&gt;proposed removing&lt;/a&gt; the Qualcomm Crypto Engine (QCE) driver — around 3,500 lines under &lt;code&gt;drivers/crypto/qce&lt;/code&gt; — from the kernel outright. The driver had already been marked broken earlier in July over its performance and bug history; the removal patch followed new measurements.&lt;/p&gt;

&lt;p&gt;The numbers in &lt;a href="https://lore.kernel.org/linux-crypto/20260724020608.GA51735@sol/" rel="noopener noreferrer"&gt;his benchmark mail&lt;/a&gt; are direct: a SHA-256 workload that takes 0.10 seconds through the ARMv8 Crypto Extensions took 10.76 seconds through QCE, using over 50 times more CPU time — much of it in hardirq and softirq context. Even with recent locking changes rolled back, the engine remained roughly 48 times slower than the CPU instructions. The offload engine costs more than it saves: per-request DMA setup, interrupts and completions dominate at typical request sizes. The discussion is ongoing — at least one developer has offered to keep maintaining the driver, and Greg Kroah-Hartman has been brought into the thread — so removal is proposed, not decided.&lt;/p&gt;

&lt;p&gt;The general lesson applies beyond Qualcomm. Crypto offload engines were useful when CPUs lacked AES and SHA instructions; on any Armv8 core with the Crypto Extensions, that assumption needs re-testing, and BSPs frequently enable vendor crypto drivers by default without anyone measuring them.&lt;/p&gt;

&lt;h3&gt;
  
  
  What to do on Qualcomm-based products
&lt;/h3&gt;

&lt;p&gt;If your BSP builds the QCE driver, benchmark both paths on your hardware — dm-crypt via &lt;code&gt;cryptsetup benchmark&lt;/code&gt;, or the kernel's tcrypt tests — before trusting the offload. Should the removal go through, nothing breaks functionally: the kernel crypto API falls back to the next-priority implementation, which on these SoCs is the faster CPU path. The same measurement habit is worth applying to any vendor offload block in your tree, not only crypto.&lt;/p&gt;

&lt;h2&gt;
  
  
  ESP32-S31 enters mass production: one chip for Wi-Fi 6, Thread and Bluetooth
&lt;/h2&gt;

&lt;p&gt;Espressif &lt;a href="https://www.espressif.com/en/news/ESP32_S31_Mass_Production" rel="noopener noreferrer"&gt;announced on 27 July&lt;/a&gt; that the ESP32-S31 has entered mass production and is available for purchase. The chip pairs two 32-bit RISC-V cores at up to 320 MHz — one with a 128-bit data path and SIMD instructions — with a 40 MHz low-power coprocessor, 512 KB of on-chip SRAM, support for 250 MHz DDR PSRAM, and up to 60 GPIOs.&lt;/p&gt;

&lt;p&gt;The radio set is the notable part. One chip carries 2.4 GHz Wi-Fi 6, Bluetooth 5.4 including both LE Audio and Classic BR/EDR, and IEEE 802.15.4 for Zigbee and Thread, plus a Gigabit Ethernet MAC. Matter is supported over both Wi-Fi and Thread, and HMI support covers camera and LCD interfaces, capacitive touch, and a 2D graphics accelerator.&lt;/p&gt;

&lt;p&gt;Be clear about what this is: a microcontroller programmed with ESP-IDF, not a Linux part. Its relevance to a Linux product is as the radio side of the design. A hub or gateway that needs Wi-Fi, Thread and Bluetooth today often carries two or three radio chips with separate antennas, drivers and certification effort; consolidating them into one part reduces board area and RF integration work. Bluetooth Classic support is increasingly rare in new silicon, which matters for products that still talk to older audio and serial-profile devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where it fits in a Linux design
&lt;/h3&gt;

&lt;p&gt;Espressif's ESP-Hosted and ESP-AT frameworks let the chip serve as a connectivity co-processor next to a Linux SoC, with the application processor driving it over SDIO, SPI or UART. For a Matter-capable gateway, that structure keeps the protocol radios and their certified stacks on one side and your Linux application on the other. Before committing a BOM, verify module-level regulatory certification for your target markets and check long-term availability terms — Espressif publishes a longevity commitment per product line, and the difference between chip and module sourcing affects both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Radxa's rCore SoMs bring Snapdragon and Dragonwing to the edge
&lt;/h2&gt;

&lt;p&gt;Radxa has &lt;a href="https://linuxgizmos.com/radxa-broadens-rcore-series-with-qualcomm-based-ai-soms/" rel="noopener noreferrer"&gt;added two Qualcomm-based system-on-modules&lt;/a&gt; to its rCore line, aimed at edge AI, multimedia, robotics and industrial products. The &lt;a href="https://radxa.com/products/rcore/rcore-q8280/" rel="noopener noreferrer"&gt;rCore-Q8280&lt;/a&gt; (50 × 80 mm) is built on the Snapdragon 8cx Gen 3 (SC8280XP): eight Kryo cores at up to 3.0 GHz, an Adreno 690 GPU, a Qualcomm AI Engine rated at 29+ TOPS, up to 32 GB of LPDDR4X, and nine PCIe Gen3 lanes. The &lt;a href="https://radxa.com/products/rcore/rcore-q6490" rel="noopener noreferrer"&gt;rCore-Q6490&lt;/a&gt; (42 × 36 mm) uses the Dragonwing QCS6490: an eight-core Kryo 670, Adreno 643, a Hexagon NPU rated at up to 12 dense TOPS, up to 16 GB of LPDDR5, and five 4-lane MIPI CSI camera interfaces supporting sensors up to 64 MP.&lt;/p&gt;

&lt;p&gt;The TOPS numbers are vendor ratings aggregated across CPU, GPU and NPU, so compare candidates by running your own model, not by the datasheet figure. The more decision-relevant numbers are the availability commitments: Radxa states the Q8280 will remain available until at least June 2029, while the Q6490 carries a commitment through at least June 2036. For an industrial product with a ten-year service life, that difference outweighs the performance gap.&lt;/p&gt;

&lt;p&gt;Software support also splits along product lines. The Q8280 lists desktop-style distributions — Debian, Ubuntu, Armbian and others — while the Q6490 lists Yocto alongside Ubuntu and Windows 11 IoT Enterprise, which signals where Radxa expects each module to be designed in. Pricing and retail availability have not been announced for either module.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to evaluate them
&lt;/h3&gt;

&lt;p&gt;Treat the two modules as different products rather than two variants of the same design. The Q8280 is a laptop-class SoC repurposed for compute-heavy edge boxes; the Q6490 is the one shaped for long-life, camera-heavy embedded designs. Before shortlisting either, ask which kernel the vendor images track, what the upgrade path looks like over the module's life, and how much of the SoC support is upstream versus carried in a vendor tree — on a Qualcomm part, that answer determines your maintenance cost more than any spec-sheet line. Get it in writing, and prototype your camera pipeline early if the five CSI interfaces are the reason you are looking at the Q6490.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lore.kernel.org/lkml/CAHk-=wiDq_aaSkBgTN=SGpa5bfTsRGvwhg8sJcFyWgPFf4x0HA@mail.gmail.com/T/#u" rel="noopener noreferrer"&gt;Linux 7.2-rc7 announcement — Linus Torvalds, lore.kernel.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.phoronix.com/news/Linux-7.2-rc7-Released" rel="noopener noreferrer"&gt;Linux 7.2-rc7 Released Following Another Exhausting AI-Driven Week — Phoronix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.ffmpeg.org/FFmpeg/FFmpeg/src/branch/release/9.0/Changelog" rel="noopener noreferrer"&gt;FFmpeg 9.0 Changelog — code.ffmpeg.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jbkempf.com/blog/2026/ffmpeg-9.0/" rel="noopener noreferrer"&gt;FFmpeg 9.0 — Jean-Baptiste Kempf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git/commit/?h=next&amp;amp;id=747b9bbbbdfdee51aee2456388f9b94b5086de4d" rel="noopener noreferrer"&gt;PCI: Add missing lockdown checks for legacy I/O and memory handlers — git.kernel.org (pci/next)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lore.kernel.org/lkml/20260724050645.223799-1-ebiggers@kernel.org/" rel="noopener noreferrer"&gt;Proposal to remove the Qualcomm QCE driver — Eric Biggers, lore.kernel.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lore.kernel.org/linux-crypto/20260724020608.GA51735@sol/" rel="noopener noreferrer"&gt;QCE vs ARMv8 CE benchmark thread — lore.kernel.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.phoronix.com/news/Qualcomm-QCE-48x-Slower" rel="noopener noreferrer"&gt;Qualcomm QCE Driver On The Chopping Block — Phoronix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.phoronix.com/news/Linux-Lockdown-Legacy-IO-Mem" rel="noopener noreferrer"&gt;Linux Accidentally Left Legacy I/O &amp;amp; Memory Handlers Open In Kernel Lockdown Mode — Phoronix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.espressif.com/en/news/ESP32_S31_Mass_Production" rel="noopener noreferrer"&gt;ESP32-S31 Now in Mass Production and Available for Purchase — Espressif Systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.espressif.com/en/products/socs/esp32-s31" rel="noopener noreferrer"&gt;ESP32-S31 product page — Espressif Systems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linuxgizmos.com/radxa-broadens-rcore-series-with-qualcomm-based-ai-soms/" rel="noopener noreferrer"&gt;Radxa Broadens rCore Series with Snapdragon and Dragonwing AI SoMs — LinuxGizmos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://radxa.com/products/rcore/rcore-q8280/" rel="noopener noreferrer"&gt;Radxa rCore-Q8280 product page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://radxa.com/products/rcore/rcore-q6490" rel="noopener noreferrer"&gt;Radxa rCore-Q6490 product page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;If you build products on the Linux kernel and want structured, instructor-led depth on kernel internals, device drivers and BSP engineering, TECH VEDA's training programs are at &lt;a href="https://www.techveda.live/" rel="noopener noreferrer"&gt;techveda.live&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.techveda.live/2026/08/11/linux-7-2-final-rc-ffmpeg-9-0/" rel="noopener noreferrer"&gt;techveda.live&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;— Raghu Bharadwaj&lt;/p&gt;

</description>
      <category>linux</category>
      <category>kernel</category>
      <category>embedded</category>
      <category>news</category>
    </item>
    <item>
      <title>Capturing a Kernel Crash Dump with kdump on ARM64</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Tue, 11 Aug 2026 05:26:01 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/capturing-a-kernel-crash-dump-with-kdump-on-arm64-43f7</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/capturing-a-kernel-crash-dump-with-kdump-on-arm64-43f7</guid>
      <description>&lt;p&gt;When a panic happens on a board on your desk, you read &lt;code&gt;dmesg&lt;/code&gt;. When it happens in the field and the register dump scrolls off a console nobody was watching, you need the memory image instead. That is what a &lt;strong&gt;kernel crash dump&lt;/strong&gt; is for. Our earlier tutorial on &lt;a href="https://www.techveda.live/2026/07/10/decode-a-kernel-oops/" rel="noopener noreferrer"&gt;decoding a kernel oops&lt;/a&gt; ended by recommending &lt;code&gt;panic_on_oops&lt;/code&gt; with kdump; this post is the part that was left out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An ARM64 target you can reboot and whose kernel command line you control (a board with U-Boot, or QEMU with &lt;code&gt;-append&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;A kernel tree you can rebuild, plus the matching &lt;code&gt;vmlinux&lt;/code&gt; with debug information.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kexec-tools&lt;/code&gt; on the target, and roughly 128 MB of RAM you can set aside.&lt;/li&gt;
&lt;li&gt;Root on the target. Every command below is run as root.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;QEMU &lt;code&gt;-M virt&lt;/code&gt; is enough to learn the mechanics. Boot it with &lt;code&gt;-kernel&lt;/code&gt; rather than UEFI firmware, because a UEFI boot leaves no &lt;code&gt;/sys/firmware/fdt&lt;/code&gt; for kexec to reuse, and give it at least &lt;code&gt;-m 2048&lt;/code&gt;. It will not reproduce the failures described at the end of this post, which are all properties of real boards.&lt;/p&gt;

&lt;h2&gt;
  
  
  What kdump does when the kernel panics
&lt;/h2&gt;

&lt;p&gt;kdump is built on &lt;code&gt;kexec&lt;/code&gt;, which boots one kernel directly from another without going back to firmware. The variant used here is &lt;code&gt;kexec -p&lt;/code&gt;, the panic path: it preloads a second kernel, the capture kernel, into memory the first kernel reserved at boot. When &lt;code&gt;panic()&lt;/code&gt;, &lt;code&gt;die()&lt;/code&gt; or the SysRq crash handler fires, the kernel calls &lt;code&gt;crash_kexec()&lt;/code&gt;, saves CPU registers as ELF notes, and jumps to that image. The address of the ELF header describing the old memory reaches the second kernel through the &lt;code&gt;elfcorehdr=&lt;/code&gt; parameter, and that memory then appears at &lt;code&gt;/proc/vmcore&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kernel configuration for a kernel crash dump
&lt;/h2&gt;

&lt;p&gt;The system kernel needs the kexec syscall; the capture kernel needs the dump-reading side. On ARM64 the same relocatable &lt;code&gt;Image&lt;/code&gt; can serve as both, so in practice you enable all of it in one config. A separate, smaller capture-kernel build is only worth the trouble if you need it to fit a smaller reservation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CONFIG_KEXEC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;y
&lt;span class="nv"&gt;CONFIG_CRASH_DUMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;y
&lt;span class="nv"&gt;CONFIG_PROC_VMCORE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;y
&lt;span class="nv"&gt;CONFIG_MAGIC_SYSRQ&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;y
&lt;span class="nv"&gt;CONFIG_DEBUG_KERNEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;y
&lt;span class="nv"&gt;CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;CONFIG_KEXEC&lt;/code&gt; (or &lt;code&gt;CONFIG_KEXEC_FILE&lt;/code&gt;, the file-descriptor-based variant that &lt;code&gt;CONFIG_KEXEC_SIG&lt;/code&gt; builds signature checking on) selects &lt;code&gt;CONFIG_KEXEC_CORE&lt;/code&gt;. &lt;code&gt;CONFIG_CRASH_DUMP&lt;/code&gt; selects &lt;code&gt;CONFIG_VMCORE_INFO&lt;/code&gt; and &lt;code&gt;CONFIG_CRASH_RESERVE&lt;/code&gt;, and enables &lt;code&gt;CONFIG_PROC_VMCORE&lt;/code&gt; by default. One point causes confusion: &lt;strong&gt;&lt;code&gt;CONFIG_DEBUG_INFO&lt;/code&gt; has no menu entry of its own any more&lt;/strong&gt; — it is selected by whichever entry you pick in the "Debug information" choice under Kernel hacking, and that choice appears only when &lt;code&gt;CONFIG_DEBUG_KERNEL&lt;/code&gt; is set. Debug information is not needed to &lt;em&gt;capture&lt;/em&gt; a dump, only to read it. Confirm what you built:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;zcat /proc/config.gz | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'CONFIG_(KEXEC|CRASH_DUMP|PROC_VMCORE)'&lt;/span&gt;
&lt;span class="nv"&gt;CONFIG_KEXEC_CORE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;y
&lt;span class="nv"&gt;CONFIG_KEXEC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;y
&lt;span class="c"&gt;# CONFIG_KEXEC_FILE is not set&lt;/span&gt;
&lt;span class="nv"&gt;CONFIG_CRASH_DUMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;y
&lt;span class="nv"&gt;CONFIG_PROC_VMCORE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;/proc/config.gz&lt;/code&gt; does not exist, the running kernel was built without &lt;code&gt;CONFIG_IKCONFIG_PROC&lt;/code&gt;; check the build tree's &lt;code&gt;.config&lt;/code&gt; instead. One ARM64 trap: &lt;code&gt;CONFIG_KEXEC&lt;/code&gt; depends on &lt;code&gt;ARCH_SUPPORTS_KEXEC&lt;/code&gt;, which on this architecture is &lt;code&gt;def_bool PM_SLEEP_SMP&lt;/code&gt;. On a uniprocessor board, or one built without suspend support, the "Enable kexec system call" prompt does not appear at all. &lt;code&gt;CONFIG_KEXEC_FILE&lt;/code&gt; has no such dependency and is the way out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reserving memory with crashkernel=
&lt;/h2&gt;

&lt;p&gt;The reservation happens at boot and cannot be done later, so it goes on the kernel command line. That timing is the point: at the moment of a panic the kernel cannot be trusted to allocate anything, so the region has to be set aside while the machine is still healthy. The simplest form gives a size and lets the kernel choose the address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;crashkernel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;128M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can pin the address with &lt;code&gt;crashkernel=128M@0xb0000000&lt;/code&gt;. &lt;strong&gt;On ARM64 an explicitly given start address must be aligned to 2 MiB (0x200000)&lt;/strong&gt;, and the reservation is refused if the region is already in use. A range form, &lt;code&gt;crashkernel=512M-2G:64M,2G-:128M&lt;/code&gt;, scales the size with the RAM present, which helps when one image ships to several board variants. For a first setup, use the plain form.&lt;/p&gt;

&lt;p&gt;Reboot with the parameter added and confirm the reservation happened. The kernel prints it, and the region appears in &lt;code&gt;/proc/iomem&lt;/code&gt; under the name &lt;code&gt;Crash kernel&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;dmesg | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; crashkernel
&lt;span class="o"&gt;[&lt;/span&gt;    0.000000] crashkernel reserved: 0x00000000b0000000 - 0x00000000b8000000 &lt;span class="o"&gt;(&lt;/span&gt;128 MB&lt;span class="o"&gt;)&lt;/span&gt;
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'crash kernel'&lt;/span&gt; /proc/iomem
  b0000000-b7ffffff : Crash kernel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If nothing is printed, the reservation failed. The kernel says so in the same log, either with &lt;code&gt;crashkernel reservation failed - memory is in use.&lt;/code&gt; for a fixed address, or a line beginning &lt;code&gt;cannot allocate crashkernel&lt;/code&gt; when no suitable region was found.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Physical memory, before and after the panic&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Physical address&lt;/th&gt;
&lt;th&gt;While the system kernel runs&lt;/th&gt;
&lt;th&gt;After &lt;code&gt;panic()&lt;/code&gt; calls &lt;code&gt;crash_kexec()&lt;/code&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0xb8000000 - 0xbfffffff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;System RAM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Preserved. Read through &lt;strong&gt;/proc/vmcore&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0xb0000000 - 0xb7ffffff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Crash kernel&lt;/strong&gt;, 128 MB. Reserved by &lt;code&gt;crashkernel=128M&lt;/code&gt;. The system kernel never allocates here; &lt;code&gt;kexec -p&lt;/code&gt; loads the capture kernel and its initramfs into it.&lt;/td&gt;
&lt;td&gt;The capture kernel runs &lt;strong&gt;here&lt;/strong&gt; — and with a plain &lt;code&gt;crashkernel=N&lt;/code&gt; reservation, only here.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x40000000 - 0xafffffff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;System RAM&lt;/strong&gt; — kernel, drivers, page cache, user space&lt;/td&gt;
&lt;td&gt;Preserved. Read through &lt;strong&gt;/proc/vmcore&lt;/strong&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Addresses are from a 2 GB board whose RAM starts at 0x40000000, pinned with &lt;code&gt;crashkernel=128M@0xb0000000&lt;/code&gt; so the output above is reproducible. The separation is the whole design: because the two kernels never share memory, the image that has to survive the crash cannot be damaged by the kernel that is crashing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loading the capture kernel with kexec -p
&lt;/h2&gt;

&lt;p&gt;Now preload the capture kernel into that reserved region. Check first that an uncompressed &lt;code&gt;Image&lt;/code&gt; is actually present on the target: &lt;strong&gt;ARM64 &lt;code&gt;kexec&lt;/code&gt; cannot load &lt;code&gt;Image.gz&lt;/code&gt;, &lt;code&gt;zImage&lt;/code&gt;, &lt;code&gt;uImage&lt;/code&gt; or a FIT image&lt;/strong&gt;, and most embedded root filesystems keep no kernel under &lt;code&gt;/boot&lt;/code&gt; at all, so copy &lt;code&gt;arch/arm64/boot/Image&lt;/code&gt; from your build tree onto the board before running the command below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;kexec &lt;span class="nt"&gt;-p&lt;/span&gt; /boot/Image &lt;span class="nt"&gt;--initrd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/boot/initramfs-kdump.img &lt;span class="nt"&gt;--append&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1 nr_cpus=1 reset_devices panic=10 console=ttyAMA0,115200"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build that initramfs before you load the capture kernel. It needs the block or network driver for wherever you intend to write, plus a minimal user space containing &lt;code&gt;makedumpfile&lt;/code&gt; and &lt;code&gt;vmcore-dmesg&lt;/code&gt;. On most embedded images the quickest route is to reuse the initramfs the board already boots with, after confirming those two binaries are in it. If the storage driver is built into the kernel rather than a module, you can drop &lt;code&gt;--initrd&lt;/code&gt; and give the capture kernel &lt;code&gt;root=/dev/mmcblk0p2 rootwait rw&lt;/code&gt; instead, so it mounts the real root filesystem and runs your normal init.&lt;/p&gt;

&lt;p&gt;Each argument here has a specific purpose. &lt;code&gt;1&lt;/code&gt; boots to single-user mode, &lt;code&gt;nr_cpus=1&lt;/code&gt; keeps the capture kernel to one CPU because it has very little memory, and &lt;code&gt;reset_devices&lt;/code&gt; asks drivers to reset their hardware rather than assume the state the crashed kernel left behind. &lt;code&gt;panic=10&lt;/code&gt; matters more than it looks: if the capture kernel itself panics, the board reboots after ten seconds instead of hanging until someone visits it. Keep the console setting, or a failure in the capture kernel is silent. No device tree is needed on the usual path: ARM64 kexec-tools reuses the running one from &lt;code&gt;/sys/firmware/fdt&lt;/code&gt; unless you pass &lt;code&gt;--dtb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Verify the image is loaded before you trust it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /sys/kernel/kexec_crash_loaded
1
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /sys/kernel/kexec_crash_size
134217728
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;0&lt;/code&gt; from the first file means no capture kernel is loaded, and a panic will simply hang or reboot. In current mainline these attributes were regrouped under &lt;code&gt;/sys/kernel/kexec/&lt;/code&gt; as &lt;code&gt;crash_loaded&lt;/code&gt; and &lt;code&gt;crash_size&lt;/code&gt;, with the old names kept as compatibility symlinks, so the paths above work on old and new kernels alike.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kexec_crash_size&lt;/code&gt; is writable: writing a smaller value shrinks the reservation and returns the rest to the system, but only while no capture kernel is loaded. To unload, run &lt;code&gt;kexec -p -u&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Triggering a panic and saving the dump
&lt;/h2&gt;

&lt;p&gt;Test the path deliberately, before you need it. SysRq gives you a crash on demand. Writing &lt;code&gt;1&lt;/code&gt; first enables all SysRq functions, because many distributions ship a restricted mask that does not include the crash trigger:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;1 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /proc/sys/kernel/sysrq
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;c &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /proc/sysrq-trigger
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The console should show the panic, then a second kernel banner. When it settles, &lt;code&gt;/proc/vmcore&lt;/code&gt; is the crashed kernel's memory. Filter it rather than copying it whole — a full copy is the size of your RAM, which is rarely what you want on a device with eMMC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;makedumpfile &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nt"&gt;--message-level&lt;/span&gt; 1 &lt;span class="nt"&gt;-d&lt;/span&gt; 31 /proc/vmcore /var/crash/vmcore
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;vmcore-dmesg /proc/vmcore &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /var/crash/dmesg.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-d 31&lt;/code&gt; is the dump level: it discards zero, cache, user and free pages and keeps kernel data, which covers most driver bugs. &lt;code&gt;-c&lt;/code&gt; compresses each page with zlib; &lt;code&gt;-l&lt;/code&gt; (LZO) and &lt;code&gt;-z&lt;/code&gt; (zstd) are usually smaller and faster, but they have to be enabled when makedumpfile is built, and the stock Yocto build has only zlib. &lt;code&gt;--message-level 1&lt;/code&gt; keeps the progress output quiet. &lt;code&gt;vmcore-dmesg&lt;/code&gt;, also from kexec-tools, extracts just the kernel log ring buffer — on a constrained target that one small file is often enough to identify the fault.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the kernel crash dump
&lt;/h2&gt;

&lt;p&gt;Reboot into the normal kernel first, then analyse offline on your workstation. The &lt;code&gt;crash&lt;/code&gt; utility is the usual tool, and it needs the &lt;em&gt;exact&lt;/em&gt; &lt;code&gt;vmlinux&lt;/code&gt; that produced the dump:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;crash vmlinux /var/crash/vmcore
      KERNEL: vmlinux
    DUMPFILE: /var/crash/vmcore  &lt;span class="o"&gt;[&lt;/span&gt;PARTIAL DUMP]
        CPUS: 4
       ... &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;, &lt;span class="nb"&gt;uptime&lt;/span&gt;, release, machine and memory lines omitted&lt;span class="o"&gt;)&lt;/span&gt;
       PANIC: &lt;span class="s2"&gt;"Kernel panic - not syncing: sysrq triggered crash"&lt;/span&gt;
crash&amp;gt; bt
crash&amp;gt; log
crash&amp;gt; ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;[PARTIAL DUMP]&lt;/code&gt; is expected: it means the file was filtered by &lt;code&gt;makedumpfile -d&lt;/code&gt; rather than copied whole. &lt;code&gt;bt&lt;/code&gt; gives the backtrace of the panicking task, &lt;code&gt;log&lt;/code&gt; the kernel ring buffer, and &lt;code&gt;ps&lt;/code&gt; the task list at the moment of the crash.&lt;/p&gt;

&lt;p&gt;Plain &lt;code&gt;gdb&lt;/code&gt; can inspect registers and memory too, but only on an uncompressed ELF dump — &lt;strong&gt;it cannot open the kdump-compressed file that &lt;code&gt;makedumpfile -c&lt;/code&gt; produces&lt;/strong&gt;. Expand it first with &lt;code&gt;makedumpfile -R&lt;/code&gt;, and expect &lt;code&gt;gdb&lt;/code&gt; to understand far less about kernel structures than &lt;code&gt;crash&lt;/code&gt; does. Reading a dump well is a skill in itself, and it is one of the areas covered in the TECH VEDA &lt;a href="https://www.techveda.live/linux-device-drivers/" rel="noopener noreferrer"&gt;Linux Device Drivers course&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where kdump fails on embedded boards
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The reservation never happened.&lt;/strong&gt; The bootloader replaced your command line, or the fixed address overlapped a carveout for a display or DSP. Check &lt;code&gt;dmesg&lt;/code&gt;, not the bootloader environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;kexec loading is blocked.&lt;/strong&gt; If the &lt;code&gt;kernel.kexec_load_disabled&lt;/code&gt; sysctl has been set to 1, &lt;code&gt;kexec -p&lt;/code&gt; fails; that sysctl cannot be set back to 0, so only a reboot clears it. A locked-down kernel refuses the legacy &lt;code&gt;kexec_load()&lt;/code&gt; path as well, leaving &lt;code&gt;kexec_file_load()&lt;/code&gt; with a signed image as the sanctioned route.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The capture kernel boots but cannot write anywhere.&lt;/strong&gt; Its initramfs must contain the storage or network driver and a userspace able to run &lt;code&gt;makedumpfile&lt;/code&gt;. This is the most common reason a setup that appears to work produces no file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The reservation is too small.&lt;/strong&gt; If the capture kernel dies during boot with allocation failures, increase it rather than guessing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The reservation cannot be placed in low memory.&lt;/strong&gt; A plain &lt;code&gt;crashkernel=128M&lt;/code&gt; is placed below 4 GB, which fails on boards whose low memory is already full of reserved-memory carveouts. Use &lt;code&gt;crashkernel=128M,high crashkernel=64M,low&lt;/code&gt; so the bulk goes above 4 GB and only the DMA-capable part stays low.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not every oops produces a dump.&lt;/strong&gt; An oops reaches &lt;code&gt;crash_kexec()&lt;/code&gt; only when &lt;code&gt;kexec_should_crash()&lt;/code&gt; agrees: in interrupt context, in the idle task or init, or when &lt;code&gt;panic_on_oops&lt;/code&gt; is set. A plain oops in ordinary process context kills the task and leaves no dump. Set &lt;code&gt;panic_on_oops=1&lt;/code&gt;, and optionally &lt;code&gt;panic_on_warn=1&lt;/code&gt;, to cover those.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The watchdog reboots the board mid-dump.&lt;/strong&gt; The SoC or PMIC watchdog keeps counting while the capture kernel boots and &lt;code&gt;makedumpfile&lt;/code&gt; runs, and nothing in that path services it. Either disable it on the capture kernel's command line, or accept &lt;code&gt;vmcore-dmesg&lt;/code&gt; only, which finishes in seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Devices left running by the crashed kernel disturb the capture kernel.&lt;/strong&gt; In-flight DMA and IOMMU contexts survive the panic, so you can see SMMU stream-ID faults or a hang as soon as the capture kernel touches that controller. Keep &lt;code&gt;reset_devices&lt;/code&gt; even when it looks unnecessary, and blacklist the offending driver on the capture kernel's command line.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building kdump into a Yocto image
&lt;/h2&gt;

&lt;p&gt;OpenEmbedded-Core carries the recipes, so nothing has to be written by hand. At the time of writing it packages kexec-tools 2.0.32, splits it into &lt;code&gt;kexec&lt;/code&gt;, &lt;code&gt;kdump&lt;/code&gt; and &lt;code&gt;vmcore-dmesg&lt;/code&gt;, and runtime-depends on &lt;code&gt;makedumpfile&lt;/code&gt;, which is also in OE-core. That dependency hangs off the &lt;code&gt;kexec-tools&lt;/code&gt; meta-package rather than off &lt;code&gt;kdump&lt;/code&gt;, so list everything you want explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;IMAGE_INSTALL:append &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;" kexec kdump vmcore-dmesg makedumpfile"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;kdump&lt;/code&gt; package installs &lt;code&gt;/etc/sysconfig/kdump.conf&lt;/code&gt; and either a sysvinit script or a &lt;code&gt;kdump.service&lt;/code&gt; unit, depending on your distro features. Set &lt;code&gt;KDUMP_KIMAGE&lt;/code&gt; to the capture kernel and &lt;code&gt;KDUMP_CMDLINE&lt;/code&gt; to the arguments above, and add &lt;code&gt;crashkernel=128M&lt;/code&gt; to the machine's command line.&lt;/p&gt;

&lt;p&gt;Three things about that script are worth knowing before you rely on it. It never passes an initrd — there is no &lt;code&gt;KDUMP_INITRD&lt;/code&gt; variable — so the capture kernel has to reach your real root filesystem on its own. Its save path runs when &lt;code&gt;/proc/vmcore&lt;/code&gt; is non-empty, which is only true &lt;em&gt;inside the capture kernel&lt;/em&gt;, so &lt;code&gt;kdump&lt;/code&gt; and &lt;code&gt;makedumpfile&lt;/code&gt; must be present in the capture environment and not merely in the normal image. And the shipped &lt;code&gt;kdump.conf&lt;/code&gt; sets &lt;code&gt;MAKEDUMPFILE_ARGS&lt;/code&gt; to &lt;code&gt;--dump-dmesg&lt;/code&gt;, so out of the box you get a kernel-log extract rather than the filtered vmcore this post produced. Change that variable if you want the full dump.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A kernel crash dump needs three things in place before the crash: a &lt;code&gt;crashkernel=&lt;/code&gt; reservation, a capture kernel loaded with &lt;code&gt;kexec -p&lt;/code&gt;, and somewhere for it to write.&lt;/li&gt;
&lt;li&gt;Verify the reservation in &lt;code&gt;dmesg&lt;/code&gt; and &lt;code&gt;/proc/iomem&lt;/code&gt;, and the load in &lt;code&gt;/sys/kernel/kexec_crash_loaded&lt;/code&gt;. Do not assume either worked.&lt;/li&gt;
&lt;li&gt;Test with &lt;code&gt;echo c &amp;gt; /proc/sysrq-trigger&lt;/code&gt; while you can still watch the console.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;makedumpfile -d 31&lt;/code&gt; to filter, and &lt;code&gt;vmcore-dmesg&lt;/code&gt; when you only need the log. The result is kdump-compressed, so read it with &lt;code&gt;crash&lt;/code&gt;, not &lt;code&gt;gdb&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On ARM64 &lt;code&gt;kexec&lt;/code&gt; loads only an uncompressed &lt;code&gt;Image&lt;/code&gt;, an explicit &lt;code&gt;crashkernel&lt;/code&gt; base must be 2 MiB aligned, and the capture kernel's initramfs must carry the driver it needs to save the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why does kdump need memory reserved at boot instead of allocating it when the crash happens?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
At the moment of a panic the kernel cannot be trusted to allocate anything. The reserved region is set aside at boot and never used by the running kernel, so the capture kernel sitting there is intact when it is needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need to build a separate capture kernel?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Not on ARM64. The architecture supports relocatable kernels, so the same &lt;code&gt;Image&lt;/code&gt; can act as both. A separate, smaller build is only worth doing if you want to fit a smaller reservation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much memory should I give to crashkernel on an embedded board?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
128 MB is a reasonable starting point. If the capture kernel fails to boot with allocation errors, raise it. You can shrink an existing reservation at runtime by writing a smaller value to &lt;code&gt;/sys/kernel/kexec_crash_size&lt;/code&gt;, but only while no capture kernel is loaded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why did my board reboot on panic without producing a dump?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Either no capture kernel was loaded, which &lt;code&gt;/sys/kernel/kexec_crash_loaded&lt;/code&gt; will tell you, or it booted but its initramfs had no driver for the storage you asked it to write to. A hardware watchdog can also reboot the board before the dump finishes. Keep a console configured in the capture kernel's command line so you can see which happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.kernel.org/admin-guide/kdump/kdump.html" rel="noopener noreferrer"&gt;Documentation for Kdump — The kexec-based Crash Dumping Solution (kernel.org)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/torvalds/linux/blob/master/kernel/crash_reserve.c" rel="noopener noreferrer"&gt;kernel/crash_reserve.c — crashkernel parsing and reservation (torvalds/linux)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/torvalds/linux/blob/master/kernel/kexec_core.c" rel="noopener noreferrer"&gt;kernel/kexec_core.c — the kexec sysfs attributes (torvalds/linux)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.openembedded.org/openembedded-core/tree/meta/recipes-kernel/kexec" rel="noopener noreferrer"&gt;kexec-tools recipe and kdump init script (OpenEmbedded-Core)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crash-utility.github.io/" rel="noopener noreferrer"&gt;The crash utility documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techveda.live/2026/07/10/decode-a-kernel-oops/" rel="noopener noreferrer"&gt;Reading a Kernel Oops, Part 2: Decode to the Source Line and Reason Backward&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>kernel</category>
      <category>embedded</category>
      <category>debugging</category>
    </item>
    <item>
      <title>SoC Kernel Support: How to Tell If Yours Has Already Lapsed</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Mon, 10 Aug 2026 17:35:02 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/soc-kernel-support-how-to-tell-if-yours-has-already-lapsed-3073</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/soc-kernel-support-how-to-tell-if-yours-has-already-lapsed-3073</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;SoC kernel support is not one date, it is three independent clocks: the upstream LTS end-of-life date, the last time your vendor's BSP branch actually moved, and whether the silicon carries a public availability commitment. All three are measurable in a few minutes, and most teams never measure any of them. We maintain a public BSP tracker covering seventeen SoCs and re-verify every field weekly against the real git refs and kernel.org; the most recent refresh was 9 August 2026. Running the measurement across that dataset: two vendor branches have not received a commit in more than 300 days, one shipping platform runs a kernel series that is not an LTS at all, and for only four is a specific silicon longevity date available in the public domain at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most embedded teams discover that their SoC kernel support has lapsed at the worst possible moment: when a CVE lands, a customer asks for a patched image, or a certification body asks how long the product will receive updates. The uncomfortable part is that the lapse is almost always visible months or years earlier, in public data, to anyone who thinks to look.&lt;/p&gt;

&lt;p&gt;This article gives the method. It is deliberately reproducible: every check below is something you can run yourself against public sources in an afternoon, and every number we quote is dated so you can re-run it and see whether it has moved.&lt;/p&gt;

&lt;p&gt;We also publish the result, because the aggregate is more instructive than any single board. TECH VEDA maintains a public BSP tracker covering seventeen SoCs, and our engineering team rechecks every field once a week against the vendors' real git refs and against kernel.org — the last refresh ran on 9 August 2026. The branch ages quoted below were re-checked directly against the GitHub API on 10 August 2026, so they can be reproduced rather than taken on trust. The living data is at &lt;a href="https://www.techveda.live/kernel-lifecycles/" rel="noopener noreferrer"&gt;kernel lifecycles&lt;/a&gt; and on the per-SoC pages linked throughout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three clocks behind SoC kernel support
&lt;/h2&gt;

&lt;p&gt;"Supported" is a word that hides three different guarantees, made by different parties, that expire at different times.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The upstream LTS clock.&lt;/strong&gt; The kernel.org stable team publishes an end-of-life date for each longterm series. After it, no more stable fixes are produced by anyone, for anybody.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The vendor branch clock.&lt;/strong&gt; Your silicon vendor maintains a BSP branch. It has a head commit, and that commit has a date. If that date stops advancing, the vendor has stopped merging fixes into the tree you are consuming, whatever the roadmap says.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The silicon longevity clock.&lt;/strong&gt; Separately from software, the vendor may commit to keeping the part orderable until a stated year. This is the one most often assumed and least often verified.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Clock&lt;/th&gt;
&lt;th&gt;What it answers&lt;/th&gt;
&lt;th&gt;Evidence to collect&lt;/th&gt;
&lt;th&gt;Risk when it expires&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Upstream kernel&lt;/td&gt;
&lt;td&gt;How long does upstream stable maintenance exist?&lt;/td&gt;
&lt;td&gt;Kernel series, kernel.org longterm list and EOL date&lt;/td&gt;
&lt;td&gt;Stable-fix and CVE cliff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vendor BSP&lt;/td&gt;
&lt;td&gt;Is the exact tree you ship still visibly maintained?&lt;/td&gt;
&lt;td&gt;Branch head committer date, release cadence, advisories&lt;/td&gt;
&lt;td&gt;Patch flow stops reaching your build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Silicon longevity&lt;/td&gt;
&lt;td&gt;How long can the part still be sourced?&lt;/td&gt;
&lt;td&gt;Published vendor lifecycle commitment&lt;/td&gt;
&lt;td&gt;Redesign and supply-chain exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These are independent. A part can have a 2045 availability commitment and a BSP branch that has not moved in eight months. A vendor can be committing daily to a branch built on a kernel that reaches end-of-life this year. &lt;strong&gt;Your actual exposure is set by whichever clock expires first, not by the one the datasheet advertises.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Clock one: the upstream end-of-life date
&lt;/h2&gt;

&lt;p&gt;Start here, because it is the cheapest to check and it caps everything else. Find your kernel series and read its projected end-of-life from kernel.org:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;
6.1.182-mydevice
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://www.kernel.org/releases.json | &lt;span class="se"&gt;\&lt;/span&gt;
    jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.releases[] | select(.moniker=="longterm") | "\(.version)  EOL \(.eol // "n/a")"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verified against kernel.org on 10 August 2026, the six longterm series stand as follows. Two of them expire this year. We keep this table current at &lt;a href="https://www.techveda.live/kernel-lifecycles/" rel="noopener noreferrer"&gt;kernel lifecycles&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Series&lt;/th&gt;
&lt;th&gt;Current&lt;/th&gt;
&lt;th&gt;Projected EOL&lt;/th&gt;
&lt;th&gt;Time remaining&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6.18&lt;/td&gt;
&lt;td&gt;6.18.44&lt;/td&gt;
&lt;td&gt;31 Dec 2028&lt;/td&gt;
&lt;td&gt;about 29 months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.12&lt;/td&gt;
&lt;td&gt;6.12.103&lt;/td&gt;
&lt;td&gt;31 Dec 2028&lt;/td&gt;
&lt;td&gt;about 29 months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.6&lt;/td&gt;
&lt;td&gt;6.6.151&lt;/td&gt;
&lt;td&gt;31 Dec 2027&lt;/td&gt;
&lt;td&gt;about 17 months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.1&lt;/td&gt;
&lt;td&gt;6.1.182&lt;/td&gt;
&lt;td&gt;31 Dec 2027&lt;/td&gt;
&lt;td&gt;about 17 months&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5.15&lt;/td&gt;
&lt;td&gt;5.15.215&lt;/td&gt;
&lt;td&gt;31 Dec 2026&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;about 5 months&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5.10&lt;/td&gt;
&lt;td&gt;5.10.264&lt;/td&gt;
&lt;td&gt;31 Dec 2026&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;about 5 months&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is a trap in this step that affects more products than the EOL dates do. &lt;strong&gt;Not every kernel a vendor ships is a longterm series at all.&lt;/strong&gt; If your kernel series does not appear on that list, it has no upstream longterm stable-maintenance window to plan against. That is not the same as having no maintenance: continued fixes may still arrive through the vendor's own release stream, a distribution, or another explicitly documented maintenance path. What it does mean is that you cannot rely on upstream, and the burden shifts to establishing what that documented path actually is. We found exactly this case in our own data, described below.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt; Check that your kernel series is on the longterm list before you check its end-of-life date. A series that is absent is not early in its upstream support window — it is outside one, and whatever maintenance it receives has to be established from the vendor rather than assumed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Clock two: is the vendor branch still moving
&lt;/h2&gt;

&lt;p&gt;This is the measurement almost nobody runs, and it is two commands. Resolve the branch head, then ask when that commit was made:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;git ls-remote https://github.com/rockchip-linux/kernel develop-6.6
1ba51b059f25533c5529b7f68186190b47d6a7b3    refs/heads/develop-6.6
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.github.com/repos/rockchip-linux/kernel/branches/develop-6.6 | &lt;span class="se"&gt;\&lt;/span&gt;
    jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.commit.commit.committer.date'&lt;/span&gt;
2025-09-01T11:22:35Z
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole check. Run it against the branch you actually build from, not the branch named in the marketing material. Record the date and re-run it quarterly; the trend matters more than any single reading.&lt;/p&gt;

&lt;p&gt;Two cautions on method. Use the &lt;em&gt;committer&lt;/em&gt; date rather than the author date, because a patch written months earlier can be merged today and the committer date is what tells you the tree is alive. And on repositories that are not on GitHub, the equivalent is a shallow clone: &lt;code&gt;git clone --depth 1 --branch &amp;lt;branch&amp;gt; &amp;lt;url&amp;gt;&lt;/code&gt; followed by &lt;code&gt;git log -1 --format=%cI&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Treat the resulting number as an investigation trigger rather than a support verdict. A quiet branch may still be supported through periodic SDK drops or a declared rebase cadence. What a long gap does establish is that you owe yourself a documented answer. As rough review triggers — our own, not an industry standard — we treat under 90 days as unremarkable, 90 to 180 days as worth raising at the next vendor call, and beyond a year with no published cadence as something to get in writing before design lock-in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clock three: the silicon longevity commitment
&lt;/h2&gt;

&lt;p&gt;The third clock is not about software at all. It is the vendor's public commitment to keep the part orderable until a stated year, and it matters because it bounds how long the software question is worth asking. This is the clock most often assumed from a sales conversation and least often traced to a published document.&lt;/p&gt;

&lt;p&gt;When we tried to pin a specific date to each of the seventeen SoCs in our tracker, requiring a public source rather than a sales claim, &lt;strong&gt;we could verify one for four of them.&lt;/strong&gt; AMD states 2045 for Zynq UltraScale+, Renesas 2038 for RZ/G2L, Qualcomm July 2036 for QCS6490, and NVIDIA January 2032 for Jetson Orin.&lt;/p&gt;

&lt;p&gt;For the other thirteen, &lt;strong&gt;no end date for that part is available in the public domain.&lt;/strong&gt; That is a finding about what a buyer can obtain without a sales conversation, and it is worth being precise about how it was reached: for each part we checked the vendor's public product page, its lifecycle or longevity documentation, and any published product-change or availability notice. Where none of those carried a date for that specific part, the cell reads "no public date".&lt;/p&gt;

&lt;p&gt;It does not mean the vendor offers nothing. Several of them operate published longevity programmes: NXP runs a Product Longevity Program offering a minimum of 10 or 15 years from launch, and ST publishes a commitment spanning 7 to 20 years, with a 10-year programme covering parts in the STM32MP13 series. The gap is between the programme and the part. Enrolment is generally documented per part number rather than per SoC family, and for these thirteen the per-part answer is not published where a buyer can find it.&lt;/p&gt;

&lt;p&gt;The practical consequence is the same either way: a commitment you cannot obtain from public documentation is one you cannot cite in a design review or pass to a customer, so ask your vendor to confirm enrolment and the end date for your exact part number in writing. A common substitute is a longevity claim from a module or system-on-module vendor; that covers the module, depends on the module vendor's own supply of the silicon, and is not interchangeable with a commitment from the chip vendor.&lt;/p&gt;

&lt;h2&gt;
  
  
  What seventeen SoCs actually look like
&lt;/h2&gt;

&lt;p&gt;We applied all three checks across all seventeen SoCs on &lt;strong&gt;10 August 2026&lt;/strong&gt;. The full table is not reproduced here, because it would be out of date within the week and we maintain a live version instead: &lt;a href="https://www.techveda.live/sbc-comparison/" rel="noopener noreferrer"&gt;SBC support status&lt;/a&gt; for development boards, sorted by how much cover is left, and the &lt;a href="https://www.techveda.live/mainline-matrix/" rel="noopener noreferrer"&gt;SoC mainline support matrix&lt;/a&gt; for the per-IP-block picture. The shape of the result on the day we measured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Branch head ages spanned 6 days to 370 days.&lt;/strong&gt; Most sat under 80 days. Two were past 300, and one SoC has no public git to measure at all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kernel bases spanned 5.15 to 6.18,&lt;/strong&gt; with one shipping platform on a series that is not on the longterm list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Four of the seventeen carried a silicon longevity date we could find in public documentation.&lt;/strong&gt; For the rest the cell reads "no public date".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three results are worth drawing out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Allwinner T507 line ships on 5.15, which reaches end-of-life in about five months.&lt;/strong&gt; There is also no public git server with release branches to measure against; the SDK is distributed as a repo manifest and archive downloads. Both facts are properties of how that vendor distributes software, and both mean an integrator cannot answer "when does my support end" from public information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jetson Orin's current JetPack ships kernel 6.8, and 6.8 is not a longterm series.&lt;/strong&gt; It does not appear on the kernel.org longterm list, so there is no upstream stable stream behind it and no projected end-of-life to plan against. Support for that platform flows entirely through NVIDIA's own releases, which is a coherent model, but it means the upstream clock gives you nothing and the vendor clock is the only one that exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Rockchip's RK3588, the newest branch is staler than the default one.&lt;/strong&gt; &lt;code&gt;develop-6.6&lt;/code&gt; last moved 343 days ago; &lt;code&gt;develop-6.1&lt;/code&gt;, which is the repository default, last moved 227 days ago. An integrator who reasonably picks the highest kernel version on offer lands on the less maintained tree. Note also that no 6.12 or 6.18 branch exists in that repository at all, so the newest kernel available there is already two LTS generations behind current.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt; The newest branch in a vendor repository is not necessarily the maintained one. Check the head date of every candidate branch before choosing, because the highest version number can be the least supported option on offer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What a stale branch does not prove
&lt;/h2&gt;

&lt;p&gt;This is the most important section in the article, because the measurement above is easy to over-read. A branch head date is a fact. What it means requires care, and there are at least five reasons a quiet branch is not evidence of an abandoned product.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public git is not the only channel.&lt;/strong&gt; Several vendors deliver production BSPs under NDA, through a support portal, or as periodic SDK releases rather than as continuous commits. A quiet public mirror can sit alongside an actively maintained internal tree that you receive as a customer. What the public branch measures is what a prospective integrator can see before signing anything, which is a real and different question.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A board vendor's fork is not the silicon vendor's tree.&lt;/strong&gt; The 370-day figure above belongs to Khadas, not Amlogic. Amlogic publishes no public vendor tree for this part at all, so the nearest observable proxy is a board vendor's fork. That is a fair thing to report about what an integrator can inspect, and an unfair thing to characterise as Amlogic neglecting the part.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Older branches are supposed to go quiet.&lt;/strong&gt; NXP's &lt;code&gt;lf-6.6.y&lt;/code&gt; and &lt;code&gt;lf-6.12.y&lt;/code&gt; have taken no commits since November 2025 while &lt;code&gt;lf-6.18.y&lt;/code&gt; is current. That is ordinary branch retirement after a migration, not decay. The question is only whether the branch &lt;em&gt;you&lt;/em&gt; build from is the current one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Some industries deliberately pin.&lt;/strong&gt; Automotive teams working with J721e typically track the branch matching a released Processor SDK rather than the newest branch, because the qualified configuration matters more than the freshest one. A pinned branch under a support contract is a different situation from a pinned branch by accident.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cadence differs legitimately.&lt;/strong&gt; ST rebases the STM32MP branch roughly every eighteen to twenty-four months by design. Measured on any given day that looks slow next to a vendor that merges weekly, but it is a stated cadence rather than a lapse.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest formulation is narrow: a stale public branch tells you that &lt;em&gt;you cannot verify from public sources&lt;/em&gt; that fixes are still flowing into the tree you build from. That is a procurement and due-diligence problem. Turning it into a claim about a vendor's intentions goes well beyond what the data supports.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt; Measure what you can see, and say only what the measurement supports. "I cannot verify that this tree is receiving fixes" is defensible and actionable. "This vendor has abandoned the part" usually is not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why these dates matter
&lt;/h2&gt;

&lt;p&gt;None of this is bookkeeping. Each SoC kernel support clock has a consequence attached, and teams usually meet them in the same order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A vulnerability lands and there is no fix to take.&lt;/strong&gt; While a series is in its upstream window, a CVE in a subsystem you ship arrives as a stable patch you can pull. After end-of-life, nobody produces that patch. Your options narrow to backporting it yourself from mainline, paying someone to do it, or shipping a known-vulnerable image. The first is expensive and needs a person who can read the subsystem; the third is increasingly not a choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Someone asks a question you cannot answer quickly.&lt;/strong&gt; This is the one that has changed most, and it is no longer a single regulation. Four triggers now reach the same set of facts from different directions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EU Cyber Resilience Act.&lt;/strong&gt; Reporting obligations for manufacturers begin on &lt;strong&gt;11 September 2026&lt;/strong&gt;: an actively exploited vulnerability in a product with digital elements must be reported within 24 hours of the manufacturer becoming aware of it. To report inside a day you must first establish whether the vulnerability is in your image, which is a question about which kernel you ship and which patches reached it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UK PSTI.&lt;/strong&gt; The product security regulations require a manufacturer to publish a &lt;em&gt;defined support period&lt;/em&gt; — in the wording of the regulations, "the minimum length of time, expressed as a period of time with an end date, for which security updates will be provided". Once published it may be extended but &lt;strong&gt;not shortened&lt;/strong&gt;. You cannot responsibly publish that date without knowing the three clocks behind it, because the commitment outlives your ability to revise it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EU Radio Equipment Directive.&lt;/strong&gt; The cybersecurity provisions of the delegated act became mandatory on 1 August 2025 for radio equipment placed on the EU market, which covers most connected embedded products with a wireless interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sector frameworks.&lt;/strong&gt; Automotive programmes work to UN Regulation No. 156 on software update management systems; industrial and medical programmes reach the same questions through their own standards and regulator guidance. A customer negotiating a support term asks it in plainer language and expects a date.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common thread is that all four ask you to state, in advance and in writing, how long a product will keep receiving security updates. That is not a policy question. It is the minimum of your three SoC kernel support clocks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A routine uplift turns into a migration.&lt;/strong&gt; Moving from one LTS to the next while you still have a choice is a planned engineering task. Doing it because your series died, or because a vendor branch stopped moving, means the same work with no schedule, and on a shipped product it drags re-validation and often re-certification behind it. The engineering content is similar; the cost is not, because unplanned work displaces whatever else was in the quarter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The part stops being orderable.&lt;/strong&gt; The longevity clock is the one that cannot be solved with software. If the silicon goes end-of-life inside your product's support window, the answer is a board respin and a new bring-up, and the lead time on that is measured in quarters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reason to measure early is that every one of these is cheaper as a decision than as an emergency.&lt;/strong&gt; A stale branch found during SoC selection changes a line in a comparison table. The same fact found when a CVE is already public changes a release plan.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt; Support lapse is rarely discovered by the team that caused it. It surfaces when an outside party — an attacker, a regulator, an auditor or a customer — asks a question with a deadline attached. Measuring the three clocks is how you find out on your own schedule instead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What to do before your next SoC selection
&lt;/h2&gt;

&lt;p&gt;Measuring SoC kernel support is only useful if it happens while you still have a choice of part. Five steps, in the order that saves the most time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check the kernel series is on the longterm list at all,&lt;/strong&gt; then read its end-of-life date. If the series is absent, all support flows through the vendor and you should price that accordingly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure the head date of every candidate branch,&lt;/strong&gt; not just the one you were pointed at. This is the step that surfaces the newest-is-not-maintained case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask for the longevity commitment in writing,&lt;/strong&gt; and check whether it covers the silicon or a module. If you cannot find a public statement, that is a question for procurement rather than an assumption to carry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compare the vendor tree against mainline for your blocks.&lt;/strong&gt; If the peripherals you depend on are upstream, a stale vendor branch is an inconvenience. If your camera, video encode or accelerator exists only in the vendor fork, that branch is your only source of fixes and its head date is your security posture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-run all of it quarterly, and record the result where the product plan lives.&lt;/strong&gt; A single reading tells you little; four readings tell you whether a tree is slowing down. Store the evidence, the date of the next review, and the condition that would force a migration — a kernel EOL, a branch crossing your staleness threshold, or a longevity date entering your support window. A number in someone's notebook is not a lifecycle plan.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Steps four and five are where this connects to the wider shift we wrote about in &lt;a href="https://www.techveda.live/2026/07/23/upstream-first-bsp-mainline/" rel="noopener noreferrer"&gt;upstream-first BSPs&lt;/a&gt; and in &lt;a href="https://www.techveda.live/2026/08/02/mainline-friendly-products/" rel="noopener noreferrer"&gt;architecting mainline-friendly products&lt;/a&gt;. The reason upstream-first lowers risk is precisely that it moves your dependency from a branch whose head date you cannot control to a tree with a published support window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to find the current numbers
&lt;/h2&gt;

&lt;p&gt;Every figure in this article goes stale, which is the point. Rather than ask you to trust a snapshot, we keep the underlying data live and re-verify it weekly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.techveda.live/sbc-comparison/" rel="noopener noreferrer"&gt;SBC support status&lt;/a&gt; — the three clocks applied to 29 development boards across these SoCs, sorted by how much cover is left, with a "fixes stop" date on each row. This is the fastest way to find your own board.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.techveda.live/mainline-matrix/" rel="noopener noreferrer"&gt;SoC mainline support matrix&lt;/a&gt; — all seventeen SoCs against each IP block, showing which peripherals are upstream and which still need the vendor tree. This is the check in step four above.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.techveda.live/kernel-lifecycles/" rel="noopener noreferrer"&gt;Kernel lifecycles&lt;/a&gt; — current patch level, release date and projected end-of-life for every longterm series, checked against kernel.org. This is clock one.&lt;/li&gt;
&lt;li&gt;Per-SoC pages carrying the BSP branch, its head date and the longevity position, including &lt;a href="https://www.techveda.live/rk3588/" rel="noopener noreferrer"&gt;RK3588&lt;/a&gt;, &lt;a href="https://www.techveda.live/qcs6490/" rel="noopener noreferrer"&gt;QCS6490&lt;/a&gt;, &lt;a href="https://www.techveda.live/jetson-orin/" rel="noopener noreferrer"&gt;Jetson Orin&lt;/a&gt; and &lt;a href="https://www.techveda.live/t507/" rel="noopener noreferrer"&gt;T507&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.techveda.live/yocto-layers/" rel="noopener noreferrer"&gt;Yocto layer compatibility&lt;/a&gt; — whether your vendor BSP layer actually has a branch for the Yocto release you are targeting, read from each layer's own git history.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A field with no primary source stays empty rather than being filled in by inference, which is why some cells read "no public date" rather than carrying a number. The wording is deliberate. It records that the figure is not obtainable from public documentation, which is the thing that affects you, and it makes no claim about what a vendor will commit to privately.&lt;/p&gt;

&lt;p&gt;If you are planning a long-lived embedded Linux product, this assessment is worth running across the whole product line rather than one board: which of your peripherals exist upstream, what a migration off a stale branch would actually cost, and where your real support cliff falls. Doing it before a CVE, a certification audit or a supply-chain event forces the question is the difference between a scheduled uplift and an unplanned migration project. That is the work our &lt;a href="https://www.techveda.live/services/#bsp" rel="noopener noreferrer"&gt;BSP and kernel engineering&lt;/a&gt; team does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;SoC kernel support runs on three independent clocks: upstream LTS end-of-life, the vendor branch head date, and the silicon longevity commitment. Your exposure is set by whichever expires first.&lt;/li&gt;
&lt;li&gt;Check that your kernel series appears on the kernel.org longterm list before checking its EOL date. Jetson Orin's current JetPack ships 6.8, which is not a longterm series.&lt;/li&gt;
&lt;li&gt;Measuring a vendor branch takes two commands, and the committer date of the branch head is the number that matters.&lt;/li&gt;
&lt;li&gt;The newest branch is not always the maintained one. Rockchip's &lt;code&gt;develop-6.6&lt;/code&gt; is 343 days stale while the default &lt;code&gt;develop-6.1&lt;/code&gt; is 227 days stale.&lt;/li&gt;
&lt;li&gt;A specific silicon longevity date is publicly available for only four of the seventeen SoCs we track. Several other vendors run published longevity programmes, but the per-part enrolment and end date are not published where a buyer can find them. Module-level claims are not silicon-level claims.&lt;/li&gt;
&lt;li&gt;The consequences are asymmetric: a stale branch found during SoC selection is a line in a comparison table, while the same fact found after a CVE is public is a release-plan problem. CRA reporting obligations from 11 September 2026 make the question harder to defer.&lt;/li&gt;
&lt;li&gt;A quiet public branch means you cannot verify that fixes are flowing, not that a vendor has abandoned a part. NDA channels, SDK releases and deliberate branch retirement all look identical from outside.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How do I check when a vendor BSP branch last moved?&lt;/strong&gt;&lt;br&gt;
Resolve the branch head with git ls-remote, then read the committer date of that commit. On GitHub-hosted trees the branches API returns it directly; elsewhere a shallow clone followed by git log -1 --format=%cI gives the same answer. Use the committer date rather than the author date, because it reflects when the change entered the tree.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My kernel version is not on the kernel.org longterm list. What does that mean?&lt;/strong&gt;&lt;br&gt;
It means the series is not receiving upstream stable maintenance and has no projected end-of-life to plan against. All fixes for that platform come from the vendor, so the vendor's release cadence becomes your only support clock.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does a stale vendor branch mean the SoC is abandoned?&lt;/strong&gt;&lt;br&gt;
No. It means you cannot verify from public sources that fixes are still reaching the tree you build from. Vendors also ship through NDA channels and periodic SDK releases, older branches are retired deliberately after a migration, and some vendors rebase on a stated eighteen to twenty-four month cadence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a ten-year longevity claim from my module supplier the same as one from the chip vendor?&lt;/strong&gt;&lt;br&gt;
No. A module vendor's commitment covers the module and depends on that vendor's own supply of the silicon. Several chip vendors run published longevity programmes, but enrolment is documented per part number and for most of the parts we track that per-part date is not in the public domain. Ask for your exact part number in writing rather than assuming family-level coverage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often should I re-run these SoC kernel support checks?&lt;/strong&gt;&lt;br&gt;
Quarterly is enough for a product in development, and the trend matters more than any single reading. Record the head dates each time, because a tree that is slowing down is visible in a series of measurements and invisible in one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.kernel.org/category/releases.html" rel="noopener noreferrer"&gt;Active kernel releases and projected end-of-life dates&lt;/a&gt; — kernel.org, the source for clock one.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.techveda.live/2026/07/09/kernel-lts-support-embedded-planning/" rel="noopener noreferrer"&gt;The Shorter Kernel LTS Support Window: What It Means for Embedded Products&lt;/a&gt; — TECH VEDA, on why clock one moves faster than it used to.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.techveda.live/2026/07/23/upstream-first-bsp-mainline/" rel="noopener noreferrer"&gt;Upstream-First BSP: Why Vendors Are Moving to Mainline&lt;/a&gt; — TECH VEDA.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.techveda.live/2026/08/02/mainline-friendly-products/" rel="noopener noreferrer"&gt;Architecting Mainline-Friendly Products&lt;/a&gt; — TECH VEDA.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.legislation.gov.uk/ukdsi/2023/9780348249767" rel="noopener noreferrer"&gt;UK Product Security regulations 2023&lt;/a&gt; — the source for the "defined support period" wording.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.nxp.com/products/nxp-product-information/nxp-product-programs/product-longevity:PRDCT_LONGEVITY_HM" rel="noopener noreferrer"&gt;NXP Product Longevity Program&lt;/a&gt; and &lt;a href="https://www.st.com/content/st_com/en/about/quality-and-reliability/product-longevity.html" rel="noopener noreferrer"&gt;ST Product Longevity&lt;/a&gt; — two examples of published vendor programmes; check enrolment for your exact part number.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/rockchip-linux/kernel/branches" rel="noopener noreferrer"&gt;rockchip-linux/kernel branch list&lt;/a&gt; and &lt;a href="https://github.com/khadas/linux/tree/khadas-linux-6.12.y" rel="noopener noreferrer"&gt;khadas/linux khadas-linux-6.12.y&lt;/a&gt; — the two trees quoted above, so the branch dates can be re-checked directly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;— Raghu Bharadwaj&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://www.techveda.live/2026/08/10/soc-kernel-support-lapsed/" rel="noopener noreferrer"&gt;TECH VEDA blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>embedded</category>
      <category>kernel</category>
      <category>iot</category>
    </item>
    <item>
      <title>What fork() Actually Costs, and Why the Process-Builder RFC Does Not Fix It Yet</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Mon, 10 Aug 2026 09:16:13 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/what-fork-actually-costs-and-why-the-process-builder-rfc-does-not-fix-it-yet-23c0</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/what-fork-actually-costs-and-why-the-process-builder-rfc-does-not-fix-it-yet-23c0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A process-builder API is proposed for Linux — &lt;code&gt;pidfd_open(0, PIDFD_EMPTY)&lt;/code&gt;, &lt;code&gt;pidfd_config()&lt;/code&gt;, &lt;code&gt;pidfd_spawn_run()&lt;/code&gt; — to construct a process incrementally instead of copying the parent with &lt;code&gt;fork()&lt;/code&gt; and discarding the copy with &lt;code&gt;exec()&lt;/code&gt;. We traced the cost argument through the kernel source at v7.1.7, and it has three parts: the mapping walk, the page-table copy for anonymous memory, and a descriptor-table copy sized by your highest descriptor number. &lt;code&gt;posix_spawn()&lt;/code&gt; already removes the first two and not the third. In its current RFC form the proposed API does not improve on that: it uses &lt;code&gt;CLONE_VM | CLONE_VFORK&lt;/code&gt; internally too, so it avoids the same two costs and still copies the descriptor table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status:&lt;/strong&gt; RFC. First series 28 May 2026 (13 patches, superseded by a redesign); second series 16 July 2026 (24 patches, against linux-next). No pidfd or exec maintainer had replied to the second series at the time of writing. Nothing described here is in a released or -rc kernel; you would have to apply the series to linux-next yourself to try it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;The practical conclusion first, because it decides whether the rest of this concerns you: this interface is not in any released kernel, and in its current form it is not faster than what &lt;code&gt;posix_spawn()&lt;/code&gt; already gives you. The useful question is not whether to wait for it, but where process creation actually costs you time and latency today. That is what most of this article is about.&lt;/p&gt;

&lt;p&gt;In May 2026, Li Chen posted a patch series to speed up a specific pattern: runtimes that repeatedly launch the same short-lived helpers. The stated target was coding agents that start &lt;code&gt;rg&lt;/code&gt;, &lt;code&gt;git&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt; and &lt;code&gt;python&lt;/code&gt; over and over. The design cached executable metadata behind a template file descriptor and spawned from that.&lt;/p&gt;

&lt;p&gt;Reviewers rejected the shape while accepting the goal. Mateusz Guzik argued it optimised the wrong end — "Most of this shaves off a tiny amount of work, while retaining the primary avoidable reason for bad performance: the very fact that fork is part of the picture, especially the part mucking with mm" — and Andy Lutomirski wrote that it was "a lot of complexity in the kernel for a teeny tiny gain". Christian Brauner proposed building on pidfds instead, modelled on &lt;code&gt;fsconfig()&lt;/code&gt;, and said that "any implementation should also allow userspace to implement posix_spawn() on top of it". Kees Cook agreed.&lt;/p&gt;

&lt;p&gt;Chen accepted the redirection and, in July, posted a 24-patch replacement following Brauner's sketch. It is a single-descriptor model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pidfd_open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PIDFD_EMPTY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/* Optional executable-path staging. */&lt;/span&gt;
&lt;span class="n"&gt;pidfd_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PIDFD_CONFIG_SET_STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="n"&gt;PIDFD_CONFIG_KEY_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;pidfd_spawn_run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The empty pidfd is "a taskless future pidfd with a stable pidfs inode, but no task, PID, or process-count charge". Live-task operations return &lt;code&gt;-ESRCH&lt;/code&gt; until the run step creates one; afterwards the same descriptor is the child's pidfd. LWN has covered both rounds, and the mailing-list threads are linked in full at the end. The rest of this article checks the performance claim against the kernel source and works out who it applies to.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we checked, and what it changes
&lt;/h2&gt;

&lt;p&gt;The usual one-line summary is that &lt;code&gt;fork()&lt;/code&gt; is expensive because it copies the process, including its memory. We traced the paths in the v7.1.7 tree. There are three separate costs, they scale with different things, and each one changes what you would do about it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, the mapping walk; second, the page-table copy.&lt;/strong&gt; These are usually described as one cost and they are not. Copy-on-write means page &lt;em&gt;contents&lt;/em&gt; are not duplicated. But page &lt;em&gt;tables&lt;/em&gt; are, for some mappings, and that is the part usually left out. The walk in &lt;code&gt;dup_mmap()&lt;/code&gt; costs one structure per virtual memory area, so it is proportional to the number of mappings. Then, per mapping, &lt;code&gt;copy_page_range()&lt;/code&gt; decides whether to copy page tables at all. Its gate, &lt;code&gt;vma_needs_copy()&lt;/code&gt;, returns false — skipping the work entirely — for mappings a fault can refill later; the comment there reads "Fork becomes much lighter when there are big shared or private readonly mappings." But it returns &lt;em&gt;true&lt;/em&gt; whenever the source mapping has an &lt;code&gt;anon_vma&lt;/code&gt;, which every private mapping acquires as soon as it is written. For those, every present page table entry is copied.&lt;/p&gt;

&lt;p&gt;So the first cost tracks the number of mappings and the second tracks resident anonymous pages. A large read-only file mapping is close to free, and a large heap is not. &lt;strong&gt;A process with twelve mappings and a two-gigabyte touched heap is twelve lines in &lt;code&gt;/proc/PID/maps&lt;/code&gt; and roughly half a million page-table entries to copy.&lt;/strong&gt; Measure both terms: &lt;code&gt;wc -l &amp;lt; /proc/PID/maps&lt;/code&gt; for the first, and &lt;code&gt;AnonRSS&lt;/code&gt; in &lt;code&gt;/proc/PID/status&lt;/code&gt; for the second. Note also that a library's writable data segment acquires an &lt;code&gt;anon_vma&lt;/code&gt; at relocation time, so "read-only libraries are free" applies to their text segments and not their data.&lt;/p&gt;

&lt;p&gt;A side effect of the walk is worth knowing if you read traces: the parent's &lt;code&gt;mmap_lock&lt;/code&gt; is held for write throughout, and each mapping is also write-locked individually as it is walked. Under per-VMA locking it is that per-mapping lock, rather than &lt;code&gt;mmap_lock&lt;/code&gt; alone, that stalls a concurrent fault in another thread.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The second cost has a delayed part.&lt;/strong&gt; Setting up copy-on-write write-protects the page-table entries of both processes, not just the child's. The line in &lt;code&gt;__copy_present_ptes()&lt;/code&gt; is commented "If it's a COW mapping, write protect it both processes", and it calls &lt;code&gt;wrprotect_ptes()&lt;/code&gt; on the source &lt;code&gt;mm&lt;/code&gt;. So after &lt;code&gt;fork()&lt;/code&gt; returns, the parent's own writable private pages are write-protected, and its next write to each one takes a minor fault.&lt;/p&gt;

&lt;p&gt;Whether that fault also copies the page depends on who else holds it. &lt;code&gt;do_wp_page()&lt;/code&gt; reuses the page in place when the folio is exclusively owned, so once the child has exec'd or exited the parent usually pays one fault per page and no copy; it pays the copy as well while the page is genuinely still shared. Either way the cost is deferred and does not appear in a benchmark that times the &lt;code&gt;fork()&lt;/code&gt; call, and the write-protect pass itself, including its TLB flush, is paid before &lt;code&gt;fork()&lt;/code&gt; returns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third, the descriptor table, sized by your highest descriptor number rather than the count.&lt;/strong&gt; The extent of the walk in &lt;code&gt;dup_fd()&lt;/code&gt; comes from &lt;code&gt;sane_fdtable_size()&lt;/code&gt;, which is built on &lt;code&gt;find_last_bit()&lt;/code&gt; over the open-descriptor bitmap and rounds up to a multiple of &lt;code&gt;BITS_PER_LONG&lt;/code&gt;. A process holding descriptors 0, 1, 2 and one stray at 100000 walks 100032 slots and allocates a table for them, against 64 slots and no allocation without the stray. Two processes with identical open-file counts can differ by three orders of magnitude on the descriptor-copying step. This is the cost that produces behaviour with no obvious cause, and it is also the one you can fix today.&lt;/p&gt;

&lt;h2&gt;
  
  
  What posix_spawn() already avoids
&lt;/h2&gt;

&lt;p&gt;One further check, because it surprises people who have read the POSIX page: &lt;strong&gt;there is no &lt;code&gt;spawn&lt;/code&gt; system call in Linux.&lt;/strong&gt; We grepped every architecture syscall table at v7.1.7 to confirm it. glibc implements &lt;code&gt;posix_spawn()&lt;/code&gt; in user space, and its own source comment says how — it "uses the clone syscall directly with CLONE_VM and CLONE_VFORK flags and an allocated stack", which today means &lt;code&gt;clone3()&lt;/code&gt; with a fallback for older kernels.&lt;/p&gt;

&lt;p&gt;That matters for a reason the RFC discussion does not draw out. &lt;code&gt;CLONE_VM&lt;/code&gt; collapses both memory-side costs to a single &lt;code&gt;mmget()&lt;/code&gt;, and &lt;code&gt;CLONE_VFORK&lt;/code&gt; is what makes sharing the address space safe, by suspending the calling thread until the child execs or exits. But glibc does &lt;em&gt;not&lt;/em&gt; pass &lt;code&gt;CLONE_FILES&lt;/code&gt;, so &lt;code&gt;posix_spawn()&lt;/code&gt; still copies the descriptor table. Of the three costs above, the C library already removes the first two and leaves the third to you.&lt;/p&gt;

&lt;p&gt;The three shapes side by side, which is the comparison the discussion rarely shows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* 1. fork() + exec(): pays all three costs */&lt;/span&gt;
&lt;span class="n"&gt;pid_t&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;execve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;envp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;127&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/* 2. posix_spawn(): CLONE_VM | CLONE_VFORK in the C library.
      Removes the mapping walk and the page-table copy.
      Still copies the descriptor table. */&lt;/span&gt;
&lt;span class="n"&gt;pid_t&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;posix_spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;envp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/* 3. The proposed builder. Not in any released kernel.
      Today it is CLONE_VM | CLONE_VFORK internally, so it
      pays what posix_spawn() pays. */&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pidfd_open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PIDFD_EMPTY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pidfd_spawn_run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What this costs on an embedded target
&lt;/h2&gt;

&lt;p&gt;The code above is the same on every architecture Linux runs on. &lt;code&gt;dup_mmap()&lt;/code&gt;, &lt;code&gt;copy_page_range()&lt;/code&gt; and &lt;code&gt;dup_fd()&lt;/code&gt; do not vary by platform. What varies is the size of each input, and which consequence you care about — and on one point, whether the system call exists at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without an MMU there is no fork().&lt;/strong&gt; On a &lt;code&gt;CONFIG_MMU=n&lt;/code&gt; build, &lt;code&gt;fork()&lt;/code&gt; returns &lt;code&gt;-EINVAL&lt;/code&gt;; the kernel source comments it "can not support in nommu mode". &lt;code&gt;vfork()&lt;/code&gt; carries no such guard, so on no-MMU targets &lt;code&gt;vfork()&lt;/code&gt; and &lt;code&gt;posix_spawn()&lt;/code&gt; are what you have. For a large class of embedded systems, then, avoiding the &lt;code&gt;fork()&lt;/code&gt; cost is not an optimisation to consider; it is already the only path available.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On PREEMPT_RT the cost is jitter, not throughput.&lt;/strong&gt; The question on a real-time system is not whether a process launches a few percent faster. It is whether a &lt;code&gt;fork()&lt;/code&gt; elsewhere on the system injects latency into unrelated real-time work. It does: the fork holds the parent's &lt;code&gt;mmap_lock&lt;/code&gt; for write, allocates, and write-protects page-table entries, which requires TLB shootdown across CPUs. The RFC's throughput numbers say nothing about this, and the shootdown cost scales with the number of pages being write-protected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A large daemon spawning small helpers.&lt;/strong&gt; Media and camera frameworks are the common case: a long-running process with a large heap and many buffer mappings launching short-lived codec or processing helpers. The heap, not the framework, is what makes it expensive. For the large device and dma-buf mappings these processes hold, &lt;code&gt;MADV_DONTFORK&lt;/code&gt; is the direct remedy — it sets &lt;code&gt;VM_DONTCOPY&lt;/code&gt; so the mapping is skipped entirely. It applies to distinct &lt;code&gt;mmap()&lt;/code&gt; regions, so it is a remedy for buffer mappings and not for a large heap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Descriptor tables are relatively more expensive on small systems.&lt;/strong&gt; The high-water-mark cost is the same code everywhere, but a descriptor table sized for number 100000 is several hundred kilobytes of pointer array plus bitmaps. On a server that is noise. On a 128 MB target already balancing media buffers, DMA heaps and graphics memory, it is not.&lt;/p&gt;

&lt;p&gt;Two things cut the other way, and they are the reason the agent-runtime framing does not transfer directly. Guzik's main objection to building the child's state in the parent is that the allocations happen on the parent's node, so a child intended to run elsewhere starts with its memory on the wrong node; on a single-node SoC that objection does not apply at all. And on a small target booting from eMMC, NAND or SPI-NOR, spawn latency is dominated by ELF loading, dynamic-linker relocation and cold-cache demand paging — the &lt;code&gt;exec&lt;/code&gt; half. Even where fork cost is measurable, it is often not the term that decides how long a spawn takes.&lt;/p&gt;

&lt;p&gt;The general shape, then: on a BusyBox shell, an init or supervisor, or a watchdog respawning a service, all three cost terms are short and there is nothing here to fix. The cost becomes real when the spawning process is large, when descriptor numbers have drifted high, or when the system has latency requirements rather than throughput requirements. The Android zygote shows the first case is solvable in user space. It starts early, loads the shared libraries and runtime that every application will need, and then waits. Applications are forked from that process rather than from a large parent, so each fork copies a small, known address space instead of whatever the parent has grown into.&lt;/p&gt;

&lt;h2&gt;
  
  
  The seccomp question nobody has answered
&lt;/h2&gt;

&lt;p&gt;One item in the July series deserves separate attention from anyone shipping a sandboxed product, and the author raised it himself rather than being caught out on it. Seccomp sees &lt;code&gt;pidfd_spawn_run()&lt;/code&gt; and cannot dereference the user pointer to inspect the path or the action records behind it. An exec-only denylist that permits unknown syscalls would therefore not block this exec. The cover letter puts it as "policy must filter the builder syscall as a unit", and ends the paragraph with an open question to reviewers rather than a decision.&lt;/p&gt;

&lt;p&gt;The operational consequence is what matters: if a builder syscall is merged, seccomp policies will have to filter it explicitly. A policy that reasons about &lt;code&gt;execve()&lt;/code&gt; today will not automatically extend to it, because seccomp cannot inspect the staged path and action data behind the user pointer. That inability is long-standing and documented, so this follows from how the interface is shaped rather than from a bug in the implementation. No reviewer has responded to the question.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the process-builder API does not do yet
&lt;/h2&gt;

&lt;p&gt;The most useful sentence in the July cover letter is the author's own assessment of what he has built: "The implementation still uses CLONE_VM | CLONE_VFORK plus exec internally", and it "does not yet construct a pristine target process without first inheriting source state". The elided sentence between those two makes clear this was deliberate — Guzik had suggested starting with vfork to begin the implementation, and that is what the RFC does.&lt;/p&gt;

&lt;p&gt;Read against the cost model above, that means the process-builder API currently does what &lt;code&gt;posix_spawn()&lt;/code&gt; already does, with a cleaner interface: it removes the two memory-side costs and not the descriptor-table copy. The pristine-process work — the part that would remove the remaining cost, argued for by Guzik and by John Ericson, who described a partially initialised process that stays unscheduled while callers install its state — is listed as follow-up. Anyone reading the headline as "process creation is about to get faster" is describing work that has not been written yet.&lt;/p&gt;

&lt;p&gt;It is also not close to replacing &lt;code&gt;posix_spawn()&lt;/code&gt; functionally. The series lists what is missing: "open and close file actions, resetids, signal masks/defaults, process groups, sessions, scheduler attributes, affinity, cgroup placement, PATH lookup/posix_spawnp(), and exec by fd."&lt;/p&gt;

&lt;h2&gt;
  
  
  What we could not verify
&lt;/h2&gt;

&lt;p&gt;Three things here are reported rather than checked, and should be read that way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We did not measure any of this.&lt;/strong&gt; The cost model above comes from reading the code at a pinned tag, not from timing it on hardware. Where we say a cost scales with something, that is what the source does, not a curve we plotted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The benchmark is the author's own.&lt;/strong&gt; The first series reported between +2.00% and +4.99% higher tool-call throughput on his own harness against a Python &lt;code&gt;subprocess&lt;/code&gt; baseline, with a later thread remark of "about +14% for printf-style work" for very short single-tool runs. We have not reproduced it. No reviewer reproduced it either, and two of them argued the gain was small regardless of the measurement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The review status is the claim most likely to be out of date by the time you read this.&lt;/strong&gt; At the time of writing, neither Brauner nor Kees Cook had replied to the July series. The two responses on the list were from Justin Suess, who argued the executable should be passed as a descriptor rather than a path string and questioned whether &lt;code&gt;pidfd_spawn_run()&lt;/code&gt; should exist rather than extending &lt;code&gt;execveat()&lt;/code&gt;, and Andy Lutomirski, replying to one patch, who flagged that checking whether a task is embryonic must happen before reading its credentials or the read is a security-relevant data race.&lt;/p&gt;

&lt;p&gt;On authorship: the July series discloses substantial LLM assistance in its cover letter and carries &lt;code&gt;Assisted-by:&lt;/code&gt; trailers on its patches. The May series did not disclose it up front — it came out when Guzik asked directly whether the work was "vibe-coded", meaning produced from an LLM prompt rather than from a working understanding of the subsystem, and Chen answered "Partly, yes". We note it because it is on the record and became part of the review discussion. It does not change the engineering question, which is whether the series can justify its interface, its security model and its performance value upstream.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do today
&lt;/h2&gt;

&lt;p&gt;None of the proposed interface is available in a released kernel. The cost model is, and it points at six things that do not depend on this RFC landing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prefer &lt;code&gt;posix_spawn()&lt;/code&gt; over &lt;code&gt;fork()&lt;/code&gt; plus &lt;code&gt;exec()&lt;/code&gt;&lt;/strong&gt; when the child setup fits within spawn attributes and file actions. It removes the mapping walk and the page-table copy, which are the two largest costs for most processes. glibc and musl both implement it with &lt;code&gt;CLONE_VM | CLONE_VFORK&lt;/code&gt;; check your C library if you ship uClibc-ng or an old Bionic. Two caveats: &lt;code&gt;CLONE_VFORK&lt;/code&gt; suspends the calling thread until the child execs or exits, which moves ELF loading and relocation onto your critical path and can be the worse trade on slow flash; and you cannot run arbitrary code between spawn and exec.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find out what your runtime actually does.&lt;/strong&gt; &lt;code&gt;strace -f -e trace=clone,clone3,vfork,execve&lt;/code&gt; on the spawning process settles in one run whether you are paying for a full &lt;code&gt;fork()&lt;/code&gt; or not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure both memory cost terms.&lt;/strong&gt; &lt;code&gt;wc -l &amp;lt; /proc/PID/maps&lt;/code&gt; gives the mapping count and &lt;code&gt;AnonRSS&lt;/code&gt; in &lt;code&gt;/proc/PID/status&lt;/code&gt; gives the anonymous footprint. A few dozen mappings and a few megabytes of anonymous memory means you have no problem. A few dozen mappings and a gigabyte heap means you do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep descriptor numbers dense.&lt;/strong&gt; The table is sized by the highest number you hold, not by how many. Close what you do not need before spawning, which &lt;code&gt;close_range()&lt;/code&gt; does in one call, and do not raise &lt;code&gt;RLIMIT_NOFILE&lt;/code&gt; beyond what you use. This is the one cost &lt;code&gt;posix_spawn()&lt;/code&gt; does not remove.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;MADV_DONTFORK&lt;/code&gt; for large inherited mappings&lt;/strong&gt; that should not cross the spawn boundary. It applies to distinct &lt;code&gt;mmap()&lt;/code&gt; regions, so it is a remedy for device and dma-buf buffers rather than for a large heap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On PREEMPT_RT, evaluate jitter rather than average throughput.&lt;/strong&gt; The cost that matters there is the latency a spawning process injects into unrelated real-time tasks, which no throughput benchmark will show you.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a large daemon must launch helpers and none of the above is enough, the structural fix is the zygote pattern described earlier: fork a small helper early and let it do the launching.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to watch upstream
&lt;/h2&gt;

&lt;p&gt;The signal that this is moving is a non-RFC posting, or an ack from the pidfd or exec maintainers on the lore thread linked below. A reply from Christian Brauner in particular would settle whether the pidfd-based shape survives. The thing to watch for after that is whether the pristine-process work appears, because that, and not the interface, is what would change the numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is the process-builder API?&lt;/strong&gt;&lt;br&gt;
It is a proposed Linux interface for constructing a new process step by step and then running it, instead of copying the parent with fork() and replacing that copy with exec(). The current RFC uses pidfd_open with the PIDFD_EMPTY flag to create an empty process handle, pidfd_config() to configure it, and pidfd_spawn_run() to start it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use the process-builder API today?&lt;/strong&gt;&lt;br&gt;
Not in a released kernel. It is an unmerged RFC patch series and the design has already changed once, so trying it means applying the patches to linux-next yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will it make process creation faster?&lt;/strong&gt;&lt;br&gt;
Not in its current form. The cover letter states the implementation still uses CLONE_VM and CLONE_VFORK plus exec internally and does not yet construct a pristine target process, so it performs about as posix_spawn() already does. The work that would remove the remaining cost is listed as follow-up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is fork() slow because it copies all the parent's memory?&lt;/strong&gt;&lt;br&gt;
Page contents are not copied, but page tables are, for any private mapping that has been written. So fork cost has two terms: one proportional to the number of mappings, and one proportional to the number of resident pages in anonymous mappings. A large read-only file mapping is nearly free; a large heap is not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which of these costs does posix_spawn() actually remove?&lt;/strong&gt;&lt;br&gt;
Two of the three. CLONE_VM removes the mapping walk and the page-table copy. It does not pass CLONE_FILES, so the descriptor table is still copied and the cost of a high descriptor number remains. Close unneeded descriptors before spawning to deal with that separately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does fork cost differ by architecture?&lt;/strong&gt;&lt;br&gt;
The code does not. dup_mmap(), copy_page_range() and dup_fd() are the same everywhere. What differs is the size of each input and which consequence matters. One real exception: on a CONFIG_MMU=n build fork() returns -EINVAL, so no-MMU targets use vfork() or posix_spawn() instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When does this actually cost me on an embedded target?&lt;/strong&gt;&lt;br&gt;
When the spawning process is large, such as a media daemon with a big heap launching codec helpers; when descriptor numbers have drifted high, since the table is sized by the highest number in use; and on PREEMPT_RT systems, where the TLB shootdown a fork requires injects latency into unrelated tasks on other cores. On a BusyBox shell or a small supervisor all three cost terms are short.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does Linux have a posix_spawn() system call?&lt;/strong&gt;&lt;br&gt;
No. There is no spawn system call in the kernel. glibc and musl implement posix_spawn() in user space using the clone family of system calls with CLONE_VM and CLONE_VFORK, which is why it avoids the address space duplication that fork() performs.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://lore.kernel.org/all/cover.1784204592.git.me@linux.beauty/" rel="noopener noreferrer"&gt;RFC PATCH 00/24 — pidfd: add a minimal process spawn builder — Li Chen, 16 July 2026&lt;/a&gt;. Quotes from Justin Suess and Andy Lutomirski are replies on this thread.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://lore.kernel.org/all/20260528095235.2491226-1-me@linux.beauty/" rel="noopener noreferrer"&gt;RFC PATCH v1 00/13 — exec: add spawn templates for repeated executable startup — Li Chen, 28 May 2026&lt;/a&gt;. Quotes from Mateusz Guzik, Andy Lutomirski, Christian Brauner and Kees Cook are replies on this thread.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lwn.net/Articles/1076018/" rel="noopener noreferrer"&gt;Moving beyond fork() + exec() — Jonathan Corbet, LWN.net, 5 June 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lwn.net/Articles/1086330/" rel="noopener noreferrer"&gt;The beginning of a process-builder API — Jonathan Corbet, LWN.net, 4 August 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elixir.bootlin.com/linux/v7.1.7/source/mm/mmap.c" rel="noopener noreferrer"&gt;mm/mmap.c at v7.1.7 — dup_mmap and the mapping walk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elixir.bootlin.com/linux/v7.1.7/source/mm/memory.c" rel="noopener noreferrer"&gt;mm/memory.c at v7.1.7 — vma_needs_copy, __copy_present_ptes and do_wp_page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elixir.bootlin.com/linux/v7.1.7/source/fs/file.c" rel="noopener noreferrer"&gt;fs/file.c at v7.1.7 — dup_fd, sane_fdtable_size and close_range&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elixir.bootlin.com/linux/v7.1.7/source/kernel/fork.c" rel="noopener noreferrer"&gt;kernel/fork.c at v7.1.7 — copy_mm, copy_files and vfork handling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man3/posix_spawn.3.html" rel="noopener noreferrer"&gt;posix_spawn(3) manual page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man2/madvise.2.html" rel="noopener noreferrer"&gt;madvise(2) manual page — MADV_DONTFORK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;— Raghu Bharadwaj&lt;/p&gt;

</description>
      <category>linux</category>
      <category>kernel</category>
      <category>embedded</category>
      <category>performance</category>
    </item>
    <item>
      <title>Linux Kernel CVEs: What to Patch by Device (2 – 8 Aug 2026)</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Sat, 08 Aug 2026 14:06:59 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/linux-kernel-cves-what-to-patch-by-device-2-8-aug-2026-2he8</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/linux-kernel-cves-what-to-patch-by-device-2-8-aug-2026-2he8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The Linux kernel project published 46 Linux kernel CVEs in the week of 2 to 8 August 2026. Every one is already fixed in a stable release. There is no 0-day and no public exploit code. The only action is to update your kernel to the fixed version for your branch. The minimum safe release per branch is 5.10.264, 5.15.215, 6.1.182, 6.6.150, 6.12.102, 6.18.43, 7.1.7, or mainline 7.2-rc5. The 6.19 and 7.0 series are end of life; move those systems to 7.1.7.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a normal-volume week, with 46 CVEs. Most are narrow driver and networking fixes. Which of these Linux kernel CVEs matter for you depends on what your product builds and how it is configured. No CVE this week has a public exploit or a CVSS score in the kernel record, so the order of work is set by how the bug is reached. A few are reachable over the air or over the network, so schedule those first where they apply. This advisory gives the version to install, then explains which CVEs matter for mobile and automotive, embedded and IoT, cloud and datacenter, and medical devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one action: update to the fixed version for your branch
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;uname -r&lt;/code&gt; to see your current kernel version. Compare it with the target for your branch in the table below. If your version is lower than the target, update to the target release. Updating to the target release for your branch clears every CVE in this week's set.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stable branch&lt;/th&gt;
&lt;th&gt;Update to at least&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5.10 LTS&lt;/td&gt;
&lt;td&gt;5.10.264&lt;/td&gt;
&lt;td&gt;Affected; the SRSO fix CVE-2026-68480 sets this point release.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5.15 LTS&lt;/td&gt;
&lt;td&gt;5.15.215&lt;/td&gt;
&lt;td&gt;Affected, same as 5.10.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.1 LTS&lt;/td&gt;
&lt;td&gt;6.1.182&lt;/td&gt;
&lt;td&gt;Current release; carries this week's 6.1 backports.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.6 LTS&lt;/td&gt;
&lt;td&gt;6.6.150&lt;/td&gt;
&lt;td&gt;Current release.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.12 LTS&lt;/td&gt;
&lt;td&gt;6.12.102&lt;/td&gt;
&lt;td&gt;Current release.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6.18 LTS&lt;/td&gt;
&lt;td&gt;6.18.43&lt;/td&gt;
&lt;td&gt;Current release.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7.1 stable&lt;/td&gt;
&lt;td&gt;7.1.7&lt;/td&gt;
&lt;td&gt;Current stable release.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mainline&lt;/td&gt;
&lt;td&gt;7.2-rc5&lt;/td&gt;
&lt;td&gt;All fixes merged.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Branches not listed were not affected this week, or their fix predates this window. The 6.19 and 7.0 series are end of life and receive no update; move those systems to 7.1.7.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mobile and automotive
&lt;/h2&gt;

&lt;p&gt;The wireless fixes matter most for phones and car head units. &lt;code&gt;CVE-2026-64571&lt;/code&gt; is an out-of-bounds read in the Wi-Fi p54 driver; a crafted frame during an EEPROM readback reads past the socket buffer, so it is reachable over the air on devices that use a p54 USB or PCI adapter (&lt;code&gt;CONFIG_P54_COMMON&lt;/code&gt;). &lt;code&gt;CVE-2026-64573&lt;/code&gt; is an out-of-bounds write in the Qualcomm Bluetooth NVM parser; a length underflow lets a 12-byte structure be written past a short firmware buffer, and Qualcomm Bluetooth parts are common in phones and head units (&lt;code&gt;CONFIG_BT&lt;/code&gt;, &lt;code&gt;CONFIG_BT_QCA&lt;/code&gt;). &lt;code&gt;CVE-2026-64586&lt;/code&gt; is a use-after-free in the Broadcom FullMAC Wi-Fi driver when the device is removed, and Broadcom Wi-Fi is widely used in mobile platforms (&lt;code&gt;CONFIG_BRCMFMAC&lt;/code&gt;). The mac80211 bugs &lt;code&gt;CVE-2026-64568&lt;/code&gt; and &lt;code&gt;CVE-2026-64570&lt;/code&gt; are double frees on the beacon and FILS discovery configuration path, and &lt;code&gt;CVE-2026-64574&lt;/code&gt; is a use-after-free reached through the per-link debugfs files; all three need &lt;code&gt;CONFIG_MAC80211&lt;/code&gt; and a software access point or multi-link setup. For connected-car network stacks, &lt;code&gt;CVE-2026-64577&lt;/code&gt; is a buffer under-run panic in the GTP-U echo path (&lt;code&gt;CONFIG_GTP&lt;/code&gt;) and &lt;code&gt;CVE-2026-64564&lt;/code&gt; is a use-after-free in SCTP (&lt;code&gt;CONFIG_IP_SCTP&lt;/code&gt;); both are reachable from the network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embedded and IoT
&lt;/h2&gt;

&lt;p&gt;The Broadcom Wi-Fi use-after-free &lt;code&gt;CVE-2026-64586&lt;/code&gt; matters here too, because many single-board computers use Broadcom FullMAC parts (&lt;code&gt;CONFIG_BRCMFMAC&lt;/code&gt;). Gateways and network-attached storage devices that run the in-kernel SMB server should apply &lt;code&gt;CVE-2026-64578&lt;/code&gt;, an out-of-bounds read that an SMB client can trigger against a crafted compound request (&lt;code&gt;CONFIG_SMB_SERVER&lt;/code&gt;). Panels and kiosks that use the IMS PCU device should apply &lt;code&gt;CVE-2026-64565&lt;/code&gt;, a heap buffer overflow driven by a malicious USB device (&lt;code&gt;CONFIG_INPUT_IMS_PCU&lt;/code&gt;); it needs USB access. Industrial gateways with USB-CAN adapters should apply &lt;code&gt;CVE-2026-64585&lt;/code&gt;, a use-after-free when an esd USB-CAN device is removed (&lt;code&gt;CONFIG_CAN_ESD_USB&lt;/code&gt;). Devices that mount removable btrfs media should apply &lt;code&gt;CVE-2026-64567&lt;/code&gt;, an out-of-bounds read from a crafted free-space cache (&lt;code&gt;CONFIG_BTRFS_FS&lt;/code&gt;). Products still on 5.10 or 5.15 are affected this week through the SRSO fix and shared driver fixes, so plan an update to 5.10.264 or 5.15.215.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud and datacenter
&lt;/h2&gt;

&lt;p&gt;The KVM guest-to-host bugs are the highest priority here. &lt;code&gt;CVE-2026-64562&lt;/code&gt; is a use-after-free where a shadow VMCS is freed while it is still referenced and a vCPU migration races a VMCLEAR. &lt;code&gt;CVE-2026-64561&lt;/code&gt; lets guest activity map pages into an invalid shadow-MMU root. &lt;code&gt;CVE-2026-68081&lt;/code&gt; leaks pinned host pages when a nested VM-Enter fails. All three apply to hosts that run nested virtualization on Intel parts (&lt;code&gt;CONFIG_KVM_INTEL&lt;/code&gt; with nested mode on). &lt;code&gt;CVE-2026-64582&lt;/code&gt; is a use-after-free in the soft-RoCE driver (&lt;code&gt;CONFIG_RDMA_RXE&lt;/code&gt;), and &lt;code&gt;CVE-2026-68082&lt;/code&gt; is an out-of-bounds read in the Ceph client that a malicious or compromised OSD can trigger (&lt;code&gt;CONFIG_CEPH_LIB&lt;/code&gt;). File servers should apply the ksmbd bug &lt;code&gt;CVE-2026-64578&lt;/code&gt; (&lt;code&gt;CONFIG_SMB_SERVER&lt;/code&gt;) and clients should apply &lt;code&gt;CVE-2026-64597&lt;/code&gt; and &lt;code&gt;CVE-2026-64598&lt;/code&gt; in the SMB client (&lt;code&gt;CONFIG_CIFS&lt;/code&gt;). On multi-tenant hosts, &lt;code&gt;CVE-2026-64581&lt;/code&gt; is a double free in the xfrm policy path that an unprivileged user can reach through user and network namespaces (&lt;code&gt;CONFIG_XFRM_USER&lt;/code&gt;), and &lt;code&gt;CVE-2026-68480&lt;/code&gt; is the SRSO speculation fix that matters where guests from different tenants share an affected AMD CPU (&lt;code&gt;CONFIG_MITIGATION_SRSO&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Medical devices
&lt;/h2&gt;

&lt;p&gt;The wireless and USB bugs are the ones to review for connected clinical devices. &lt;code&gt;CVE-2026-64573&lt;/code&gt; in the Qualcomm Bluetooth parser matters for wearables, patient monitors, and hearing devices that use Bluetooth (&lt;code&gt;CONFIG_BT&lt;/code&gt;). The Wi-Fi bugs &lt;code&gt;CVE-2026-64571&lt;/code&gt; (p54) and &lt;code&gt;CVE-2026-64586&lt;/code&gt; (Broadcom) matter for clinical devices on wireless networks (&lt;code&gt;CONFIG_P54_COMMON&lt;/code&gt;, &lt;code&gt;CONFIG_BRCMFMAC&lt;/code&gt;). &lt;code&gt;CVE-2026-64565&lt;/code&gt; matters for bedside units with USB input peripherals (&lt;code&gt;CONFIG_INPUT_IMS_PCU&lt;/code&gt;). For networked clinical devices that carry DICOM or HL7 and FHIR over IP, &lt;code&gt;CVE-2026-64564&lt;/code&gt; in SCTP is relevant, because SCTP carries signaling in some clinical and telecom stacks (&lt;code&gt;CONFIG_IP_SCTP&lt;/code&gt;); devices that expose an SMB share should also apply &lt;code&gt;CVE-2026-64578&lt;/code&gt; (&lt;code&gt;CONFIG_SMB_SERVER&lt;/code&gt;). Medical-device patching is gated by validation and regulatory revalidation, under US FDA postmarket cybersecurity guidance, the EU Medical Device Regulation (MDR), and IEC 62304, so the action is to plan the stable kernel update through the manufacturer's change-control process rather than to apply it ad hoc.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check which Linux kernel CVEs apply to you
&lt;/h2&gt;

&lt;p&gt;There are three questions.&lt;/p&gt;

&lt;p&gt;First, version. Run &lt;code&gt;uname -r&lt;/code&gt; and compare it with the table above. If your release is below the target for your branch, update to the target. This clears every CVE in this week's set for your branch.&lt;/p&gt;

&lt;p&gt;Second, configuration. Check your kernel config for the feature behind each CVE. For example, run &lt;code&gt;zcat /proc/config.gz | grep CONFIG_BT&lt;/code&gt;, or check &lt;code&gt;CONFIG_MAC80211&lt;/code&gt;, &lt;code&gt;CONFIG_P54_COMMON&lt;/code&gt;, &lt;code&gt;CONFIG_SMB_SERVER&lt;/code&gt;, &lt;code&gt;CONFIG_IP_SCTP&lt;/code&gt;, &lt;code&gt;CONFIG_KVM_INTEL&lt;/code&gt;, or &lt;code&gt;CONFIG_BRCMFMAC&lt;/code&gt;. If the feature is not built, the matching CVE cannot affect you.&lt;/p&gt;

&lt;p&gt;Third, reachability, which sets the order of work. Over-the-air and network-reachable bugs come first: the Wi-Fi bug &lt;code&gt;CVE-2026-64571&lt;/code&gt;, the Bluetooth bug &lt;code&gt;CVE-2026-64573&lt;/code&gt;, and the network bugs &lt;code&gt;CVE-2026-64564&lt;/code&gt; (SCTP), &lt;code&gt;CVE-2026-64577&lt;/code&gt; (GTP-U) and &lt;code&gt;CVE-2026-64578&lt;/code&gt; (ksmbd). Local unprivileged bugs come next, such as the xfrm double free &lt;code&gt;CVE-2026-64581&lt;/code&gt;. Guest-to-host bugs come after that on shared virtualization hosts, led by &lt;code&gt;CVE-2026-64562&lt;/code&gt;. Bugs that need privilege or a specific configuration come last.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Update to the target release for your branch: 5.10.264, 5.15.215, 6.1.182, 6.6.150, 6.12.102, 6.18.43, 7.1.7, or mainline 7.2-rc5.&lt;/li&gt;
&lt;li&gt;Schedule the over-the-air and network-reachable bugs first: CVE-2026-64571 (Wi-Fi), CVE-2026-64573 (Bluetooth), CVE-2026-64564 (SCTP), CVE-2026-64577 (GTP-U), and CVE-2026-64578 (ksmbd).&lt;/li&gt;
&lt;li&gt;On virtualization hosts, apply the KVM guest-to-host bugs CVE-2026-64562, CVE-2026-64561, and CVE-2026-68081.&lt;/li&gt;
&lt;li&gt;The 6.19 and 7.0 series are end of life; move those systems to 7.1.7.&lt;/li&gt;
&lt;li&gt;The SRSO fix CVE-2026-68480 sets the newest required point release on every LTS branch, including 5.10 and 5.15.&lt;/li&gt;
&lt;li&gt;None of these are 0-days; all fixes are already in stable. Use your kernel config to remove the CVEs that do not apply, and test the update on your own hardware.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is the one thing I should do?&lt;/strong&gt;&lt;br&gt;
Update to the target release for your branch. Then use your kernel config and device type to decide what to test first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which ones should I schedule first?&lt;/strong&gt;&lt;br&gt;
The over-the-air and network-reachable bugs: CVE-2026-64571 (Wi-Fi p54), CVE-2026-64573 (Bluetooth QCA), CVE-2026-64564 (SCTP), CVE-2026-64577 (GTP-U), and CVE-2026-64578 (ksmbd SMB server). None has public exploit code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are any of these a 0-day?&lt;/strong&gt;&lt;br&gt;
No. All 46 CVEs are already fixed in stable, and there is no public exploit code. The action is to schedule the stable update through your normal process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I run virtualization hosts. Which CVEs apply?&lt;/strong&gt;&lt;br&gt;
The KVM guest-to-host bugs CVE-2026-64562, CVE-2026-64561, and CVE-2026-68081. They apply to hosts running nested virtualization on Intel parts, so they need CONFIG_KVM_INTEL with nested mode on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We do not build Wi-Fi, Bluetooth or the SMB server. Do these affect us?&lt;/strong&gt;&lt;br&gt;
Each bug is gated by a kernel config option. If CONFIG_MAC80211, CONFIG_P54_COMMON, CONFIG_BT and CONFIG_SMB_SERVER are not built, those bugs cannot affect you. Check your config to remove the ones that do not apply.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lore.kernel.org/linux-cve-announce/?q=d:20260802..20260809" rel="noopener noreferrer"&gt;linux-cve-announce, 2 to 8 August 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-64562" rel="noopener noreferrer"&gt;CVE-2026-64562 (KVM nVMX)&lt;/a&gt; and &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-64561" rel="noopener noreferrer"&gt;CVE-2026-64561 (KVM x86)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-64571" rel="noopener noreferrer"&gt;CVE-2026-64571 (Wi-Fi p54)&lt;/a&gt; and &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-64573" rel="noopener noreferrer"&gt;CVE-2026-64573 (Bluetooth QCA)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-64578" rel="noopener noreferrer"&gt;CVE-2026-64578 (ksmbd)&lt;/a&gt; and &lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-64564" rel="noopener noreferrer"&gt;CVE-2026-64564 (SCTP)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cve.org/CVERecord?id=CVE-2026-68480" rel="noopener noreferrer"&gt;CVE-2026-68480 (x86 SRSO Safe-RET)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kernel.org/releases.json" rel="noopener noreferrer"&gt;kernel.org active releases (6.19 and 7.0 are end of life)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>kernel</category>
      <category>security</category>
      <category>embedded</category>
    </item>
    <item>
      <title>Choosing an A/B Update Layout for Your Product</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Sat, 08 Aug 2026 05:13:01 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/choosing-an-ab-update-layout-for-your-product-8en</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/choosing-an-ab-update-layout-for-your-product-8en</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Symmetric A/B — two equal root filesystem slots — is the right default for most connected products: install to the inactive slot, reboot into it, and fall back automatically if the new software fails its health check, all while the device keeps running during the write. Limited storage, slow boot, or an application that ships on its own schedule make asymmetric, split, or rescue-augmented layouts the better choice instead. The decision is not whether to use A/B, but which A/B update layout matches your constraint.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most embedded Linux teams accept early that field updates need redundancy: keep a known-good copy so an interrupted or faulty update cannot leave the device unbootable. The usual answer is an &lt;strong&gt;A/B update layout&lt;/strong&gt; — two slots the device switches between. But "A/B" is not a single design. Each layout is tuned to a different constraint, and choosing the wrong one costs storage, boot time, or availability you did not account for. This post describes the common layouts on their merits and maps each to the scenario where it is the right choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The context
&lt;/h2&gt;

&lt;p&gt;An A/B update layout answers the interrupted-update problem, and the mechanism is common to every form — the rollback cycle shown below. What differs is how four factors are balanced, and those factors often conflict. &lt;strong&gt;Storage&lt;/strong&gt;: a second full root filesystem roughly doubles the rootfs space. &lt;strong&gt;Availability&lt;/strong&gt;: some layouts keep the application running during the update, while others must reboot into an update mode. &lt;strong&gt;Boot time and bootloader complexity&lt;/strong&gt;: where the kernel and device tree sit affects both. &lt;strong&gt;Release cadence&lt;/strong&gt;: if the base system and application ship on different schedules, updating them together wastes bandwidth.&lt;/p&gt;

&lt;p&gt;That shared rollback cycle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the bundle into the inactive slot.&lt;/li&gt;
&lt;li&gt;Mark that slot as the next boot target.&lt;/li&gt;
&lt;li&gt;Reboot into it.&lt;/li&gt;
&lt;li&gt;Run early boot and application-level health checks.&lt;/li&gt;
&lt;li&gt;Mark the slot good only after the checks pass.&lt;/li&gt;
&lt;li&gt;Fall back automatically if a boot counter or watchdog detects a failure.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The A/B update layouts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Symmetric root-fs slots
&lt;/h3&gt;

&lt;p&gt;Two root partitions of equal size, A and B. Running from A, an update installs into B, and the reverse when running from B; both slots hold equivalent software, including the main application. To keep the design simple, the kernel and device tree live inside the rootfs (usually in &lt;code&gt;/boot&lt;/code&gt;), which requires a bootloader that understands the rootfs type. RAUC describes this as probably the most common setup.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Slot A — active&lt;/th&gt;
&lt;th&gt;Slot B — inactive (update target)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;rootfs + kernel/DTB (/boot)&lt;/td&gt;
&lt;td&gt;rootfs + kernel/DTB (/boot)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The two slot entries in &lt;code&gt;system.conf&lt;/code&gt; look like this, with the mandatory &lt;code&gt;[system]&lt;/code&gt; section omitted for brevity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/rauc/system.conf
&lt;span class="go"&gt;[slot.rootfs.0]
device=/dev/mmcblk0p2
type=ext4
bootname=system-a

[slot.rootfs.1]
device=/dev/mmcblk0p3
type=ext4
bootname=system-b
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Advantages: an update can start from either slot while the application keeps running; the bootloader fallback logic stays simple; and the process is easy for technicians and users to reason about. The new software takes effect only after a reboot into the updated slot and a passing health check. The reasons to look elsewhere are limited storage, or a need for more redundancy or update flexibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Asymmetric slots
&lt;/h3&gt;

&lt;p&gt;When storage is very limited, replace the second full partition with a small "update" (or rescue) partition alongside the full "main" system. To update, the device reboots into the small update system, which writes the new image into the main slot and switches back. Being small, that system usually fits entirely in RAM as a kernel with an internal initramfs (a raw slot). It is a temporary update environment, not a preserved recovery image; that is a separate design, covered below. The costs, as RAUC states them: two reboots per update; a failed update leaves the main application unavailable until a later update succeeds; and any data that must survive in the main slot must be saved elsewhere first and restored afterwards, because the slot is overwritten.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;main — full rootfs (active)&lt;/th&gt;
&lt;th&gt;update — kernel + initramfs, runs in RAM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Split (multiple) slots
&lt;/h3&gt;

&lt;p&gt;Separate the application from the base root filesystem so each updates on its own schedule — useful when a different team owns the application, or when several applications reuse one base. RAUC models it with an &lt;code&gt;appfs&lt;/code&gt; slot whose &lt;code&gt;parent&lt;/code&gt; is the rootfs slot. You can also split the boot files (kernel) into their own slot to reduce boot time and bootloader complexity. Split slots layer on top of a symmetric or asymmetric setup. One caution from RAUC: it cannot currently guarantee compatibility between a rootfs and an appfs when a bundle updates only one of them, so always build bundles that contain every required slot, or enforce compatibility in your own release process.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Base&lt;/th&gt;
&lt;th&gt;Slot A&lt;/th&gt;
&lt;th&gt;Slot B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;rootfs&lt;/td&gt;
&lt;td&gt;base system&lt;/td&gt;
&lt;td&gt;base system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;appfs&lt;/td&gt;
&lt;td&gt;application&lt;/td&gt;
&lt;td&gt;application&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Symmetric A/B plus a rescue slot
&lt;/h3&gt;

&lt;p&gt;A rescue slot is a deliberately preserved recovery environment, distinct from the temporary update system of an asymmetric layout; normal updates never write to it. It guards against failure modes that can disable both A and B at once: a latent software error undetected across releases; corruption from mishandled power failures when slots are mounted read-write; or a configuration error that fails both slots the same way. The bootloader starts the rescue system after repeated boot failures of the normal slots, or on user request.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rescue — never written by updates&lt;/th&gt;
&lt;th&gt;Slot A — rootfs&lt;/th&gt;
&lt;th&gt;Slot B — rootfs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The decision: matching the layout to the product
&lt;/h2&gt;

&lt;p&gt;Match the A/B update layout to the dominant constraint. The table gives the quick mapping; the notes below cover the cases that need judgement.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layout&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;th&gt;Main benefit&lt;/th&gt;
&lt;th&gt;Main cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Symmetric A/B&lt;/td&gt;
&lt;td&gt;Most connected products&lt;/td&gt;
&lt;td&gt;Simple rollback; device runs during the write&lt;/td&gt;
&lt;td&gt;Two full rootfs slots&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asymmetric&lt;/td&gt;
&lt;td&gt;Tight flash budgets&lt;/td&gt;
&lt;td&gt;Lower storage requirement&lt;/td&gt;
&lt;td&gt;Two reboots and update-mode downtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Split slots&lt;/td&gt;
&lt;td&gt;Separate app and base release cycles&lt;/td&gt;
&lt;td&gt;Independent update cadence&lt;/td&gt;
&lt;td&gt;Compatibility management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A/B plus rescue&lt;/td&gt;
&lt;td&gt;Remote or high-consequence devices&lt;/td&gt;
&lt;td&gt;Recovery path if both normal slots fail&lt;/td&gt;
&lt;td&gt;More storage and boot logic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table maps each layout to its constraint; three points do not fit in a table. Use a proven framework — RAUC, SWUpdate, or Mender — rather than scripting slot selection and rollback yourself; when you can afford the space, symmetric is easier to operate than asymmetric. With split slots, enforce rootfs/appfs compatibility in your bundle policy so a partial update cannot pair mismatched versions. And pair a rescue slot with a read-only, verified rootfs (see our note on &lt;a href="https://www.techveda.live/2026/08/03/dm-verity-read-only-rootfs/" rel="noopener noreferrer"&gt;how dm-verity keeps a read-only rootfs verified&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Slot layout is only one part of a safety-relevant update strategy: secure boot, signed bundles, watchdog validation, and failure analysis are also required. Payload size is a separate choice too — whichever A/B update layout you pick, frameworks support delta or adaptive payloads to cut download size, decided independently of the layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consequences
&lt;/h2&gt;

&lt;p&gt;Storage follows directly from the A/B update layout: symmetric roughly doubles the rootfs, split avoids duplicating a shared base or heavy assets across slots, and asymmetric trades storage for reboots and downtime. In every layout, keep application state and user data on a &lt;em&gt;separate writable partition&lt;/em&gt;, not inside the slots, so it survives updates and is not duplicated — this also removes the asymmetric layout's need to save and restore that data around the overwrite. Treat that partition as its own design problem: power-fail-safe writes, a schema that still loads after a rollback to older software, and integrity or encryption where the product needs it.&lt;/p&gt;

&lt;p&gt;Someone must own the bootloader boot-selection logic and a hardware watchdog so that a boot hang counts as a failure and triggers fallback. Symmetric keeps this simple; splitting boot files or adding a rescue slot adds selection cases to maintain in U-Boot, GRUB, or Barebox. Symmetric A/B on a standard framework is well understood and easy to hand to new engineers; asymmetric and split layouts concentrate more logic and more failure modes, so document them. The build-system layers that realize these layouts — &lt;code&gt;meta-rauc&lt;/code&gt; or &lt;code&gt;meta-swupdate&lt;/code&gt; — are part of the earlier &lt;a href="https://www.techveda.live/2026/08/05/yocto-vs-buildroot-choosing-a-build-system-for-your-product/" rel="noopener noreferrer"&gt;Yocto versus Buildroot decision&lt;/a&gt;, and integrating them is covered in our &lt;a href="https://www.techveda.live/embedded-linux-yocto/" rel="noopener noreferrer"&gt;Embedded Linux on Edge AI course&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The question is not whether to use A/B, but which A/B update layout fits your constraint; the comparison table maps each to its scenario.&lt;/li&gt;
&lt;li&gt;In every layout the new software is activated only after a reboot and a health check, with automatic fallback to the previous slot on failure.&lt;/li&gt;
&lt;li&gt;Keep mutable state on a separate writable partition in every layout; slot layout is one part of a strategy that also needs secure boot, signed bundles, and a watchdog.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Which A/B update layout should I start with?&lt;/strong&gt;&lt;br&gt;
Symmetric root-fs slots, unless storage is too limited to hold two full root filesystems. It is the simplest robust layout and lets updates run while the device keeps working.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why would I choose asymmetric slots?&lt;/strong&gt;&lt;br&gt;
When storage cannot hold two full root filesystems. You keep one full main system and a small update or rescue system, at the cost of two reboots per update and the main application being unavailable if an update fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does a rescue slot protect against?&lt;/strong&gt;&lt;br&gt;
Failures that disable both A and B together: a latent bug that spreads across releases, corruption from power loss on read-write slots, or a configuration error that fails both slots identically. Normal updates never write to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where should the kernel and device tree live?&lt;/strong&gt;&lt;br&gt;
In the simplest symmetric layout they sit inside the rootfs, under /boot, which needs a bootloader that understands the rootfs type. Splitting them into a separate slot can reduce boot time and bootloader complexity. The exact implications depend on the bootloader, filesystem support, and image format, so treat boot-artifact placement as a per-platform decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rauc.readthedocs.io/en/latest/scenarios.html" rel="noopener noreferrer"&gt;RAUC Scenarios — symmetric, asymmetric, multiple, and rescue slots&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rauc.readthedocs.io/en/latest/basic.html" rel="noopener noreferrer"&gt;RAUC Basics — slots, boot confirmation and fallback&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sbabic.github.io/swupdate/scenarios.html" rel="noopener noreferrer"&gt;SWUpdate — update strategy examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mender.io/engineers/how-mender-works" rel="noopener noreferrer"&gt;Mender — how over-the-air updates work&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.techveda.live/2026/08/08/ab-update-layout-scenarios/" rel="noopener noreferrer"&gt;Tech Veda&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>embedded</category>
      <category>linux</category>
      <category>iot</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Embedded Linux Boot Time: The Phase You Are Not Measuring</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Fri, 07 Aug 2026 06:49:30 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/embedded-linux-boot-time-the-phase-you-are-not-measuring-4b8j</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/embedded-linux-boot-time-the-phase-you-are-not-measuring-4b8j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A board spends its boot time in four phases: ROM and SPL, U-Boot proper, the kernel, and user space. Each one has its own clock, and each clock starts at zero. That matters because the &lt;code&gt;dmesg&lt;/code&gt; timestamp of &lt;code&gt;0.000000&lt;/code&gt; is not power-on, so measuring the kernel alone tells you nothing about the two phases before it. This article walks through the four phases, shows how to put them on a single axis using a timestamped serial log, and covers measuring the bootloader with &lt;code&gt;bootstage&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every embedded Linux product eventually gets a boot time requirement. A backup camera has to show an image within two seconds. An industrial controller has to answer a fieldbus request before the master times out. A battery device has to finish booting before the wake budget is spent.&lt;/p&gt;

&lt;p&gt;The requirement usually arrives late, and the response is usually the same. Someone opens &lt;code&gt;dmesg&lt;/code&gt;, finds the slowest line, and starts working on it. Two weeks later the number has barely moved.&lt;/p&gt;

&lt;p&gt;The engineer did not pick a bad target. The problem is that &lt;code&gt;dmesg&lt;/code&gt; shows only one of the four phases a board goes through, and its clock starts at zero after two of the others have already finished. You can spend a long time optimizing something that was never the expensive part.&lt;/p&gt;

&lt;p&gt;So this article is about measuring rather than tuning. Once you have a timeline that runs from power-on to the moment your application is ready, the decisions get easy and usually small. Without one, you are guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why boot time work usually goes wrong
&lt;/h2&gt;

&lt;p&gt;Three things about the boot path make it hard to reason about until you instrument it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Each phase has its own clock.&lt;/strong&gt; The kernel log timestamp of &lt;code&gt;0.000000&lt;/code&gt; is not power-on. It is the moment the kernel started running and printk timestamping became available. Everything the ROM, the SPL, and U-Boot did before that is not part of that number. On a board with slow storage and a large U-Boot, the time you cannot see is often longer than the entire kernel phase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time spent working and time spent waiting look identical.&lt;/strong&gt; An initcall that takes 900 ms might be doing 900 ms of work. It might also be doing 5 ms of work and waiting 895 ms for a regulator, a clock, or a firmware file. The log line reads the same either way, and optimizing a driver that was blocked on something else saves you nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In user space, a slow unit is not always a blocking unit.&lt;/strong&gt; A service that takes 400 ms to start may not be on the critical path at all. If three other services start alongside it and the slowest takes 900 ms, removing your 400 ms service changes the ready time by zero.&lt;/p&gt;

&lt;p&gt;Put those together and the result is a familiar pattern. A team spends two weeks removing kernel configuration options, ships an image 30 percent smaller, and finds that boot time moved by 40 ms. The real cost was a 1.2 second driver initialization sequence in U-Boot that nobody had measured.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four phases, and the handoffs between them
&lt;/h2&gt;

&lt;p&gt;Agree on where each phase starts and ends before you instrument anything. The handoffs between them are where measurements get lost.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Clock starts at&lt;/th&gt;
&lt;th&gt;Measured with&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. ROM and SPL&lt;/td&gt;
&lt;td&gt;power-on&lt;/td&gt;
&lt;td&gt;scope or switched supply, no console output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. U-Boot proper&lt;/td&gt;
&lt;td&gt;U-Boot timer init&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bootstage&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Kernel&lt;/td&gt;
&lt;td&gt;kernel entry&lt;/td&gt;
&lt;td&gt;&lt;code&gt;initcall_debug&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. User space&lt;/td&gt;
&lt;td&gt;init exec&lt;/td&gt;
&lt;td&gt;&lt;code&gt;systemd-analyze&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One external clock on the serial line joins phases 2, 3 and 4. Phase 1 needs hardware.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1: ROM and SPL
&lt;/h3&gt;

&lt;p&gt;The SoC boot ROM runs from mask ROM, reads a boot mode strap or fuse, and loads a small first-stage image into on-chip SRAM. That image is the SPL, or TF-A BL2 on many Arm platforms. The SPL brings up DRAM, which is the reason it exists. Nothing bigger can run until the DDR controller is trained and calibrated.&lt;/p&gt;

&lt;p&gt;On most platforms this phase prints almost nothing, and two things dominate its cost: how fast the ROM reads from the boot medium, and how long DDR training takes. On some DDR4 and LPDDR4 platforms training runs to several hundred milliseconds. A few vendors let you save the trained parameters so later boots skip the full sequence, which is worth asking about early.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 2: U-Boot proper
&lt;/h3&gt;

&lt;p&gt;U-Boot relocates itself to DRAM, initializes drivers, reads the environment, loads the kernel, device tree, and initramfs, verifies signatures if you use verified boot, and jumps to the kernel.&lt;/p&gt;

&lt;p&gt;This is where unmeasured time builds up most often, because U-Boot sets up devices the kernel will set up again a second later. The duplication is not automatic: under the U-Boot driver model, a device that is bound but never probed costs very little. But any subsystem your boot path actually touches and your product does not need is time spent twice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 3: kernel
&lt;/h3&gt;

&lt;p&gt;The kernel decompresses itself, sets up memory management and the scheduler, runs initcalls in level order, mounts the root filesystem, and executes the init process. Almost all of the variable cost is in initcalls and in waiting for the root device to appear. The kernel's own instrumentation is the &lt;code&gt;initcall_debug&lt;/code&gt; boot parameter, which logs every initcall with a duration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 4: user space
&lt;/h3&gt;

&lt;p&gt;The init system starts services until it reaches the unit or target your application depends on. On most product images that is systemd, and the number worth having is &lt;code&gt;systemd-analyze critical-chain&lt;/code&gt;, not the total.&lt;/p&gt;

&lt;p&gt;Notice what all four have in common. &lt;strong&gt;The requirement you were given is measured from power-on, and every tool in the standard set measures from the start of its own phase.&lt;/strong&gt; Joining them up is a separate job, and it is the one most teams skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building one timeline across all four phases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The problem: four clocks, no shared zero
&lt;/h3&gt;

&lt;p&gt;U-Boot's &lt;code&gt;bootstage&lt;/code&gt; timestamps start when U-Boot's timer is available. The kernel's printk timestamps start when the kernel starts. &lt;code&gt;systemd-analyze&lt;/code&gt; reports a kernel time, an initrd time, and a userspace time, but its idea of "kernel time" begins where the bootloader handed over. None of these share an origin with the moment power was applied or the reset line was released.&lt;/p&gt;

&lt;p&gt;Adding the phase totals together gets you close, but it leaves out the ROM time and every handoff gap along the way. Those gaps are exactly where unaccounted time usually is.&lt;/p&gt;

&lt;h3&gt;
  
  
  The fix: an external clock on the serial line
&lt;/h3&gt;

&lt;p&gt;What works is timestamping the serial console from outside the board, so one clock covers everything the board prints, from the first SPL character to your application's ready message.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;grabserial&lt;/code&gt; does this. It reads the serial port, adds a timestamp to each line, and can reset its base time when a line matches a pattern, so you can anchor zero on a marker you choose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grabserial &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; /dev/ttyUSB0 &lt;span class="nt"&gt;-b&lt;/span&gt; 115200 &lt;span class="nt"&gt;-e&lt;/span&gt; 30 &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"U-Boot SPL"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reset the board with power rather than a warm reset, because a warm reset can skip ROM work that a cold boot performs. Capture the whole log to a file. That file becomes your timeline, and you read every later measurement against it.&lt;/p&gt;

&lt;p&gt;Two settings make the log easier to work with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build the kernel with &lt;code&gt;CONFIG_PRINTK_TIME=y&lt;/code&gt;, or pass &lt;code&gt;printk.time=1&lt;/code&gt;, so kernel lines carry their own timestamps as well. The kernel records the timestamp internally either way and exports it through &lt;code&gt;/dev/kmsg&lt;/code&gt;; the option controls whether it appears in console output.&lt;/li&gt;
&lt;li&gt;The console itself costs time. A serial console at 115200 baud with 8N1 framing carries ten bits per character, so it moves about 11.5 kilobytes per second, and a verbose boot can spend hundreds of milliseconds printing. Measure with the console on to find your targets, then measure again with &lt;code&gt;quiet&lt;/code&gt; to see the production number. Do not confuse the two.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What the serial line cannot show you
&lt;/h3&gt;

&lt;p&gt;This method has one limit, and it is worth being clear about it. The serial timeline begins at the first character the board prints, which on most platforms is the first SPL message. Everything before that is invisible: the boot ROM reading the SPL off eMMC, SD, or SPI-NOR prints nothing, so none of it reaches the log.&lt;/p&gt;

&lt;p&gt;Measure that interval separately, with hardware. Trigger the boot from something you can observe — a switched supply, a controlled reset line, or a scope probe on the reset signal and the serial TX line. What you get is the ROM read plus the SPL load, and on a slow boot medium that interval can be large.&lt;/p&gt;

&lt;p&gt;You only have to measure it once. It rarely changes between software builds, so take it per board and per boot medium, write it down, and record it with the four phase totals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measuring the bootloader with bootstage
&lt;/h2&gt;

&lt;p&gt;U-Boot can time its own boot, and most people never turn it on. Enable &lt;code&gt;CONFIG_BOOTSTAGE&lt;/code&gt; in &lt;code&gt;boot/Kconfig&lt;/code&gt; and it records timing marks at known points. There are two ways to read them back:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CONFIG_BOOTSTAGE_REPORT&lt;/code&gt; prints a timing summary automatically before U-Boot hands off to the OS.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CONFIG_CMD_BOOTSTAGE&lt;/code&gt; adds the &lt;code&gt;bootstage&lt;/code&gt; command, so you can run &lt;code&gt;bootstage report&lt;/code&gt; from the prompt. This is a separate symbol from the report option, and it depends on &lt;code&gt;BOOTSTAGE&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The report is a table of marks in microseconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=&amp;gt; bootstage report
Timer summary in microseconds:
       Mark    Elapsed  Stage
          0          0  reset
    213,405    213,405  board_init_f
    418,772    205,367  board_init_r
    724,190    305,418  main_loop
    944,318    220,128  bootm_start
  1,204,551    260,233  start_kernel

Accumulated time:
                 41,220  dm_spl
                162,663  dm_r
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Elapsed column is the one to read, and it is easy to read it backwards. &lt;strong&gt;Elapsed is the time between the previous mark and this one, not the time spent inside the stage the row is named after.&lt;/strong&gt; The 305,418 microseconds on the &lt;code&gt;main_loop&lt;/code&gt; row is therefore the interval from &lt;code&gt;board_init_r&lt;/code&gt; to &lt;code&gt;main_loop&lt;/code&gt;, which is where U-Boot initializes drivers and reads its environment.&lt;/p&gt;

&lt;p&gt;Read that way, the intervals here rank as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;305 ms&lt;/strong&gt;, &lt;code&gt;board_init_r&lt;/code&gt; to &lt;code&gt;main_loop&lt;/code&gt; — driver initialization and environment work in U-Boot proper.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;260 ms&lt;/strong&gt;, &lt;code&gt;bootm_start&lt;/code&gt; to &lt;code&gt;start_kernel&lt;/code&gt; — image load, signature verification, and kernel decompression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;220 ms&lt;/strong&gt;, &lt;code&gt;main_loop&lt;/code&gt; to &lt;code&gt;bootm_start&lt;/code&gt; — environment processing and boot command parsing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;213 ms&lt;/strong&gt;, reset to &lt;code&gt;board_init_f&lt;/code&gt; — SPL work and relocation, as U-Boot's own timer sees it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;205 ms&lt;/strong&gt;, &lt;code&gt;board_init_f&lt;/code&gt; to &lt;code&gt;board_init_r&lt;/code&gt; — early init and relocation into DRAM.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Accumulated section at the bottom narrows the largest item further. Of that 305 ms interval, 162,663 microseconds went on driver model probes in U-Boot proper (&lt;code&gt;dm_r&lt;/code&gt;), against 41,220 in the SPL (&lt;code&gt;dm_spl&lt;/code&gt;). If you need more detail than that, &lt;code&gt;bootstage_mark_name()&lt;/code&gt; lets you add marks of your own around whichever subsystem you suspect, then rebuild.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reducing bootloader time
&lt;/h2&gt;

&lt;p&gt;Once you know where the bootloader spends its time, there are two options inside U-Boot itself and a third that belongs to the phase before it. None of them is tuning. All are decisions someone has to sign off on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reduce U-Boot's driver set.&lt;/strong&gt; Anything U-Boot probes and never uses is time spent twice, because the kernel probes it again a moment later. Network, USB, and display are the usual candidates on a product that boots from local storage. They are almost always there for a factory or recovery path, which means the answer is usually two build configurations rather than one stripped-down one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Falcon mode.&lt;/strong&gt; &lt;code&gt;CONFIG_SPL_OS_BOOT&lt;/code&gt; lets the SPL load and start the kernel directly, skipping U-Boot proper altogether. That removes the whole of phase 2, and on some designs it is the largest single saving available to you. It also costs you the U-Boot command line, the environment, and the normal update and recovery path, so most products keep a way back into full U-Boot. &lt;code&gt;doc/develop/falcon.rst&lt;/code&gt; in the U-Boot tree describes how it works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Saved DDR training parameters.&lt;/strong&gt; This one belongs to phase 1 and depends on your SoC: some vendors let you save the trained parameters so later boots skip the full calibration. It reduces time in the phase that is hardest to instrument, which is why it is worth raising with your vendor early rather than late.&lt;/p&gt;

&lt;p&gt;One warning if your product uses verified boot. All three of these affect signing. Two U-Boot configurations means two signing paths to maintain through the release process, and Falcon mode changes which component verifies the kernel.&lt;/p&gt;

&lt;h2&gt;
  
  
  A worked example
&lt;/h2&gt;

&lt;p&gt;The numbers below are constructed rather than taken from one particular project. This is a common form of the problem, and the arithmetic is what makes the argument concrete, so it is worth walking through.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the team expected
&lt;/h3&gt;

&lt;p&gt;An industrial gateway on an i.MX8M Plus, booting from eMMC. The requirement is four seconds from power-on to the first camera frame on the display. Measured boot time is 11.0 seconds.&lt;/p&gt;

&lt;p&gt;The kernel image is 9.8 MB, which feels large to everyone who looks at it. So the plan is two weeks of kernel configuration work, plus an evaluation of whether moving the image from Yocto to Buildroot would help. &lt;strong&gt;Nobody has measured anything except the total.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What the timeline shows
&lt;/h3&gt;

&lt;p&gt;An afternoon of measurement produces this split:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ROM and SPL, up to U-Boot proper (scope plus serial log)&lt;/td&gt;
&lt;td&gt;0.4 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;U-Boot proper (&lt;code&gt;bootstage report&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;2.9 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kernel (&lt;code&gt;dmesg&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;3.2 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User space (&lt;code&gt;systemd-analyze&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;4.5 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11.0 s&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first thing to notice is that 3.3 seconds of the 11 happen before the kernel starts, and none of it appears in &lt;code&gt;dmesg&lt;/code&gt;. The team had been reading a log that begins after almost a third of the boot is already over.&lt;/p&gt;

&lt;p&gt;Inside U-Boot, &lt;code&gt;bootstage report&lt;/code&gt; puts 1.6 of the 2.9 seconds in USB and Ethernet initialization, and the Accumulated &lt;code&gt;dm_r&lt;/code&gt; figure confirms most of it is driver model probing. Both subsystems exist for a TFTP recovery path. The boot script calls &lt;code&gt;usb start&lt;/code&gt; and brings the interface up unconditionally, so the cost is paid on every boot, including the deployed units that never use that path.&lt;/p&gt;

&lt;h3&gt;
  
  
  What changes
&lt;/h3&gt;

&lt;p&gt;Splitting U-Boot into a factory configuration with USB and Ethernet, and a production configuration without them, removes 1.6 seconds. That is an afternoon of work against the two weeks that had been planned, and the kernel configuration is never touched. The 9.8 MB image ships.&lt;/p&gt;

&lt;p&gt;It is worth being honest about what this does not do. Removing 1.6 seconds from 11.0 leaves 9.4, against a requirement of four. The bootloader was not the whole problem, and finding the rest means measuring the kernel and user space, which is a separate investigation. What the afternoon established is that two weeks of kernel configuration work would have produced very little.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it costs
&lt;/h3&gt;

&lt;p&gt;Two U-Boot configurations now have to be maintained. Because the product uses verified boot, that also means two signing paths and two sets of keys to keep track of through the release process. There is a further risk that is easy to miss: the factory configuration and the production configuration can diverge, and a fault introduced in one may only appear on the production line, which is the worst place to find it. None of that is free. It is still smaller than two weeks spent on the wrong phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  A bootloader measurement checklist
&lt;/h2&gt;

&lt;p&gt;Here is the whole sequence for the first two phases, in order. On a board you already have running it takes about an hour.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Measure the interval from reset release to the first serial character once, with a scope or a controlled supply. This is your ROM and SPL-load cost, and it will not appear in any software log.&lt;/li&gt;
&lt;li&gt;Connect a host to the serial console and start &lt;code&gt;grabserial&lt;/code&gt; with an anchor pattern on the first SPL message.&lt;/li&gt;
&lt;li&gt;Power cycle the board. Do not use a warm reset. Capture the full log to a file.&lt;/li&gt;
&lt;li&gt;Enable &lt;code&gt;CONFIG_BOOTSTAGE&lt;/code&gt; and &lt;code&gt;CONFIG_CMD_BOOTSTAGE&lt;/code&gt; in U-Boot, boot, and run &lt;code&gt;bootstage report&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Record the Elapsed column, reading each value as the interval before that mark rather than time spent inside the named stage.&lt;/li&gt;
&lt;li&gt;Check the Accumulated section for &lt;code&gt;dm_spl&lt;/code&gt; and &lt;code&gt;dm_r&lt;/code&gt;. Those totals tell you how much of the bootloader's time is driver model probing.&lt;/li&gt;
&lt;li&gt;Compare U-Boot's own total against the same interval in your &lt;code&gt;grabserial&lt;/code&gt; log. If they disagree, the difference is a handoff gap, and you want to know where it is.&lt;/li&gt;
&lt;li&gt;Repeat with &lt;code&gt;quiet&lt;/code&gt; on the kernel command line to get the production number rather than the instrumented one.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What this means in practice
&lt;/h2&gt;

&lt;p&gt;For the first day, treat boot time as a measurement problem. It becomes an engineering problem after that, and not before. Get an external clock onto the serial line so all four phases sit on one axis. Measure the pre-console ROM interval with hardware, because no amount of software will show it to you. And instrument the bootloader before you touch the kernel, because &lt;strong&gt;the phase you cannot see in &lt;code&gt;dmesg&lt;/code&gt; is often the expensive one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the bootloader does turn out to account for most of your budget, the options above are design decisions with real costs attached, and you want to base them on a measurement rather than a guess. If it does not, the afternoon was still worth spending: you have ruled out two whole phases, and whatever remains is in the kernel or user space. That is a much smaller place to look.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Boot time spans four phases with four independent clocks. &lt;code&gt;dmesg&lt;/code&gt; timestamps start at kernel entry, not at power-on, so kernel-only measurement misses everything before it.&lt;/li&gt;
&lt;li&gt;Join the phases with an external timestamp on the serial console. &lt;code&gt;grabserial&lt;/code&gt; with an anchor pattern is the standard method, and a cold power cycle is required.&lt;/li&gt;
&lt;li&gt;The interval before the first serial character cannot be measured in software. Use a scope or a controlled supply, once per board and boot medium.&lt;/li&gt;
&lt;li&gt;U-Boot has built-in timing: &lt;code&gt;CONFIG_BOOTSTAGE&lt;/code&gt; for the marks, &lt;code&gt;CONFIG_BOOTSTAGE_REPORT&lt;/code&gt; to print automatically, &lt;code&gt;CONFIG_CMD_BOOTSTAGE&lt;/code&gt; for the &lt;code&gt;bootstage report&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;Elapsed is the interval before each mark, not the time spent inside the named stage. Reading it the other way inverts your conclusions.&lt;/li&gt;
&lt;li&gt;The Accumulated section separates driver model probe time in the SPL (&lt;code&gt;dm_spl&lt;/code&gt;) from U-Boot proper (&lt;code&gt;dm_r&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The structural bootloader options are a reduced driver set, Falcon mode, and saved DDR training parameters. All trade against update, recovery, or vendor dependency, and all interact with verified boot signing.&lt;/li&gt;
&lt;li&gt;The console costs real time: 115200 baud with 8N1 framing is about 11.5 kilobytes per second. Measure with it on to find targets, and again with &lt;code&gt;quiet&lt;/code&gt; to report the production number.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Why does dmesg show a boot time much shorter than what I measure with a stopwatch?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because the kernel's printk timestamp starts at zero when the kernel starts running, not at power-on. Everything the boot ROM, the SPL, and U-Boot did before that point is outside the number. On boards with slow storage or long DDR training, that interval can exceed the whole kernel phase. To see it, timestamp the serial console from outside the board with a tool such as grabserial, enable &lt;code&gt;CONFIG_BOOTSTAGE&lt;/code&gt; in U-Boot, and measure the pre-console ROM interval with a scope or a controlled supply.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What exactly does the Elapsed column in bootstage report mean?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is the time between the previous mark and that mark, not the time spent inside the stage the row is named after. So an Elapsed value on the &lt;code&gt;start_kernel&lt;/code&gt; row is the interval from &lt;code&gt;bootm_start&lt;/code&gt; to &lt;code&gt;start_kernel&lt;/code&gt;. Reading it as "time spent in start_kernel" will point you at the wrong stage. The Accumulated section at the bottom is different: those values are totals for driver model probing in the SPL (&lt;code&gt;dm_spl&lt;/code&gt;) and in U-Boot proper (&lt;code&gt;dm_r&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I measure the boot ROM, when it prints nothing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You cannot do it in software, because there is no log until the SPL starts printing. Use hardware: a switched supply or a controlled reset line, and a scope probe on the reset signal and the serial TX line. The interval from reset release to the first serial character is the ROM read plus the SPL load. It does not usually change between software builds, so measure it once per board and per boot medium and carry it as a fixed number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does turning off the serial console actually change boot time?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, and usually by more than people expect. A console at 115200 baud with 8N1 framing carries about 11.5 kilobytes per second, so a verbose boot can spend hundreds of milliseconds doing nothing but printing. Keep it on while you are looking for targets, since it is your measurement instrument. Then take a second measurement with &lt;code&gt;quiet&lt;/code&gt; on the command line, and report that one, because it is the number the product will actually have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.u-boot.org/en/latest/develop/falcon.html" rel="noopener noreferrer"&gt;U-Boot: Falcon mode&lt;/a&gt; — booting the kernel directly from the SPL.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html" rel="noopener noreferrer"&gt;The kernel's boot parameter list&lt;/a&gt; — including &lt;code&gt;printk.time=&lt;/code&gt; and &lt;code&gt;quiet&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tbird20d/grabserial" rel="noopener noreferrer"&gt;grabserial&lt;/a&gt; — Tim Bird's serial timestamping tool.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>embedded</category>
      <category>kernel</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Kernel &amp; Embedded News: AI-Written Patch Rules; AMD Ryzen X100</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Thu, 06 Aug 2026 14:52:51 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/kernel-embedded-news-ai-written-patch-rules-amd-ryzen-x100-2b71</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/kernel-embedded-news-ai-written-patch-rules-amd-ryzen-x100-2b71</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This edition tracks how Linux is governed, scheduled, and where its AI now runs. The kernel documentation tree carries new guidelines for tool-generated content, which set expectations for AI-assisted patches. The sched_ext framework is close to supporting a hierarchy of sub-schedulers together with proxy execution. And two moves push inference outward: AMD's Ryzen AI Embedded X100 folds CPU, GPU, and NPU behind one memory space for robots, while Google's LiteRT.js runs on-device models straight in the browser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The threads this edition are accountability and placement: who is responsible for a machine-generated patch, how a scheduler divides CPU time without losing correctness, and where AI inference runs — on a consolidated robotics SoC, or inside the browser itself. None of these is a finished product on its own, but each shapes how engineering teams will plan work over the next few cycles.&lt;/p&gt;

&lt;h2&gt;
  
  
  In this edition
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The kernel documents its expectations for tool-generated patches.&lt;/strong&gt; A new &lt;a href="https://docs.kernel.org/process/generated-content.html" rel="noopener noreferrer"&gt;Guidelines for Tool-Generated Content&lt;/a&gt; page has entered the process documentation, asking contributors to be transparent about tools, including AI, and to defend everything they submit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;sched_ext gains sub-schedulers and proxy execution.&lt;/strong&gt; Work on &lt;a href="https://lwn.net/Articles/1082717/" rel="noopener noreferrer"&gt;enqueue() for sub-schedulers&lt;/a&gt; lets a BPF scheduler be attached to a control group, and a long-standing incompatibility with proxy execution is being resolved.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AMD announces the Ryzen AI Embedded X100 for robots.&lt;/strong&gt; The &lt;a href="https://newsroom.amd.com/news/aai-2026-ryzen-ai-embedded-x100/" rel="noopener noreferrer"&gt;X100 Series&lt;/a&gt; combines up to 16 Zen 5 cores, an integrated GPU, and an NPU on one SoC with unified memory, sampling now with production expected in Q4 2026.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google's LiteRT.js runs inference in the browser.&lt;/strong&gt; &lt;a href="https://developers.googleblog.com/litertjs-googles-high-performance-web-ai-inference/" rel="noopener noreferrer"&gt;LiteRT.js&lt;/a&gt; executes &lt;code&gt;.tflite&lt;/code&gt; models locally through WebGPU, which is relevant to any embedded product whose interface is a web UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The kernel now documents how it handles tool-generated patches
&lt;/h2&gt;

&lt;p&gt;The kernel's process documentation has gained a page titled &lt;a href="https://docs.kernel.org/process/generated-content.html" rel="noopener noreferrer"&gt;Kernel Guidelines for Tool-Generated Content&lt;/a&gt;. It is visible in the current documentation build (7.2.0-rc6), filed under the policy guides and developer statements, next to a separate &lt;a href="https://docs.kernel.org/process/coding-assistants.html" rel="noopener noreferrer"&gt;AI Coding Assistants&lt;/a&gt; page. This is guidance, not an enforcement mechanism, and it is deliberately framed around tools in general rather than AI alone.&lt;/p&gt;

&lt;p&gt;The scope is drawn carefully. Routine tooling stays out of scope: reformatting with &lt;code&gt;clang-format&lt;/code&gt;, &lt;code&gt;rustfmt&lt;/code&gt; or Lindent, spelling and grammar fixes, identifier completion, and mechanical changes such as variable renaming. The guidelines apply when a meaningful amount of a contribution was not written by a person in the &lt;code&gt;Signed-off-by&lt;/code&gt; chain. The examples named include &lt;code&gt;checkpatch.pl --fix&lt;/code&gt;, Coccinelle scripts, a chatbot-generated function, a C file first produced by a coding assistant and then cleaned up by hand, and a changelog written by a generative model.&lt;/p&gt;

&lt;p&gt;The core requirement is transparency and accountability. Contributors are asked to state, in the cover letter or changelog, which tools were used, the input given to them, a summary of prompts for longer sessions, which parts of the change were affected, and how the result was tested. The document rests on the existing Developer Certificate of Origin and states the expectation plainly: you must understand and be able to defend everything you submit, and if you cannot, you should not send it. Maintainers keep full discretion, from treating a patch normally to rejecting a machine-generated series without detailed review.&lt;/p&gt;

&lt;p&gt;This lands against a sharper backdrop. In a mid-July mailing-list message, Linus Torvalds said the kernel is not an anti-AI project and that contributors who object to others using AI can fork the tree or step away. Separately, in the earlier discussions around AI tagging policy, he observed that a mandatory tagging rule mainly constrains people who already follow rules, while bad actors will not self-identify. Both points are worth keeping in view when reading the guidelines, and both are drawn from secondary coverage rather than primary posts.&lt;/p&gt;

&lt;p&gt;For teams, the practical change is to your submission checklist, not your build. If your group already uses Coccinelle, &lt;code&gt;checkpatch.pl --fix&lt;/code&gt; or a coding assistant, add a short provenance note to the changelog now, before a maintainer asks. The heavier point is cultural: the burden of understanding a patch stays with the human who signs it, so treat generated code as a draft to be reviewed line by line, not as output to be forwarded. That is the same standard good reviewers already applied; the value here is that it is written down and can be pointed to.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it means for kernel contributors
&lt;/h3&gt;

&lt;p&gt;If you send patches upstream, fold this into your workflow now. When a tool produced a meaningful part of a change, say so in the changelog or cover letter: name the tool, give the input, and describe what you did with the output. This page mandates no specific tag — plain, honest prose satisfies it — but where AI was involved, pair that prose with the &lt;code&gt;Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2]&lt;/code&gt; tag the AI Coding Assistants page recommends, and remember that the same page says an AI agent must never add a &lt;code&gt;Signed-off-by&lt;/code&gt; tag: only the human submitter can certify the DCO. For example, in a changelog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;conversion&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;produced&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;Coccinelle&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="n"&gt;below&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;
&lt;span class="n"&gt;reviewed&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="n"&gt;adjusted&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="n"&gt;hand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Tested&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;rcutorture&lt;/span&gt; &lt;span class="n"&gt;selftests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

  &lt;span class="err"&gt;@@&lt;/span&gt; &lt;span class="n"&gt;expression&lt;/span&gt; &lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="err"&gt;@@&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;kfree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;kfree_sensitive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reviewer can then judge the change with the right context, and you have met the transparency the document expects.&lt;/p&gt;

&lt;h2&gt;
  
  
  sched_ext gains sub-schedulers and proxy execution
&lt;/h2&gt;

&lt;p&gt;The extensible scheduler class, &lt;code&gt;sched_ext&lt;/code&gt;, lets a custom CPU scheduler be loaded as a set of BPF programs. Recent work, described by Jonathan Corbet, brings the ability to build a hierarchy of sub-schedulers close to completion, and ends a long-standing incompatibility with proxy execution.&lt;/p&gt;

&lt;p&gt;A sub-scheduler associates a &lt;code&gt;sched_ext&lt;/code&gt; scheduler with a control group, so every process in that group is managed by the attached scheduler. A capability mechanism lets a parent share part of its access downward: a newly attached sub-scheduler starts with access to no CPUs, and its parent then grants it a specific set. The design work in the &lt;code&gt;enqueue()&lt;/code&gt; path is about keeping control groups isolated from one another while avoiding needless calls up through the hierarchy, which would otherwise cost performance.&lt;/p&gt;

&lt;p&gt;Proxy execution is the other half. It addresses priority inversion by letting a task that holds a lock run on behalf of a higher-priority task that is waiting for it. Making that cooperate with sched_ext matters for realtime and latency-sensitive workloads, which are common in embedded and industrial systems, because a scheduler that cannot handle priority inheritance correctly will produce latency spikes that are hard to diagnose.&lt;/p&gt;

&lt;p&gt;Custom schedulers are attractive when a general-purpose policy leaves performance on a mixed workload, where latency-critical and throughput tasks share the same cores. The trade-off is that you now own a scheduler, and BPF scheduling is a skill your team either has or has to build. Sub-scheduler support makes the model more practical for multi-tenant and container hosts, where per-group policies are exactly what you want.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to try it
&lt;/h3&gt;

&lt;p&gt;You can experiment with sched_ext on a mainline kernel today. Build a kernel with the extensible scheduler class and BPF support enabled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;CONFIG_SCHED_CLASS_EXT&lt;/span&gt;=&lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="n"&gt;CONFIG_BPF&lt;/span&gt;=&lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="n"&gt;CONFIG_BPF_SYSCALL&lt;/span&gt;=&lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="n"&gt;CONFIG_BPF_JIT&lt;/span&gt;=&lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="n"&gt;CONFIG_DEBUG_INFO_BTF&lt;/span&gt;=&lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then build and load one of the in-tree example schedulers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;make &lt;span class="nt"&gt;-j&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; tools/sched_ext
&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; ./tools/sched_ext/build/bin/scx_simple
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the scheduler running, &lt;code&gt;/sys/kernel/sched_ext/state&lt;/code&gt; reports that a BPF scheduler is active; stop the binary and the kernel reverts to its default scheduler. The &lt;code&gt;scx_simple&lt;/code&gt; example runs a global weighted virtual-time policy, and the &lt;a href="https://github.com/sched-ext/scx" rel="noopener noreferrer"&gt;sched-ext/scx&lt;/a&gt; project carries fuller schedulers to read and adapt. Trying a sample scheduler first is the cheapest way to decide whether a custom policy is worth owning.&lt;/p&gt;

&lt;h2&gt;
  
  
  AMD's Ryzen AI Embedded X100 targets robots and the industrial edge
&lt;/h2&gt;

&lt;p&gt;AMD used its Advancing AI 2026 event to announce the &lt;a href="https://newsroom.amd.com/news/aai-2026-ryzen-ai-embedded-x100/" rel="noopener noreferrer"&gt;Ryzen AI Embedded X100 Series&lt;/a&gt;, a family of embedded processors aimed at what it calls physical AI: robotics, industrial automation, healthcare, and aerospace and defense. Each part combines up to 16 Zen 5 CPU cores, a discrete-class integrated GPU, and an NPU on a single SoC, tied together by a unified memory architecture that AMD says improves determinism and lowers latency. AMD has not published a maximum memory capacity for the series; its own benchmark configurations used 64 GB and 128 GB of LPDDR5x, so treat exact capacity as unconfirmed until the system-on-module partners publish real specifications. The parts are rated for industrial use, with a -40 to 105 C operating range and 24/7 operation for up to ten years.&lt;/p&gt;

&lt;p&gt;The number worth attention is not the TOPS rating; it is the unified memory architecture. A typical robot today spreads its compute across a control board, a separate GPU, and an inference accelerator, and moving data between them costs latency and predictability. Placing the CPU, GPU, and NPU behind one memory space removes those cross-device copies, which is what a real-time control loop actually needs.&lt;/p&gt;

&lt;p&gt;That raises the harder question for anyone building on it: real-time behavior. A robot has to run deterministic control alongside AI inference, and doing that on an x86 Linux SoC is a systems problem, not a benchmark. AMD's answer is to pair Linux with the Xen hypervisor for mixed-criticality partitioning, so a real-time control domain can run beside the AI and GPU workloads. Teams still have to decide where PREEMPT_RT, CPU isolation, and partitioning fit, because the chip does not remove latency on its own.&lt;/p&gt;

&lt;p&gt;The software stack is the other decision. AMD is pushing an open stack — Linux, the ROCm stack for the integrated GPU, and frameworks such as PyTorch and ONNX — with tools to migrate CUDA code to ROCm. That answers NVIDIA's Jetson line and its CUDA ecosystem, but the real test is whether ROCm runs cleanly on this embedded part under the exact kernel you ship, worth confirming on real hardware rather than a reference image.&lt;/p&gt;

&lt;p&gt;Two caveats keep this in proportion. AMD's headline comparisons, such as up to 2.1 times the multi-threaded CPU performance of an Intel Core Ultra Series 3 part, are its own projections measured on a proxy processor configured to represent the top X100 model, not independent numbers on final silicon. And the series is not shipping yet: sampling began in June 2026, with production expected in the fourth quarter through system-on-module partners. It is a platform to evaluate now and design around later, not one to build a shipping product on today.&lt;/p&gt;

&lt;h3&gt;
  
  
  What it means for engineering teams
&lt;/h3&gt;

&lt;p&gt;Even before silicon ships, there is work to scope, and the early decisions are about the software platform. If you are evaluating the X100 for a real-time product, decide whether you run a PREEMPT_RT kernel or partition the machine with a hypervisor, and how you isolate the control cores from the AI and GPU load — the usual levers are boot parameters such as &lt;code&gt;isolcpus&lt;/code&gt; and &lt;code&gt;nohz_full&lt;/code&gt; plus IRQ affinity. Confirm early that the ROCm stack and its kernel driver build and load against the kernel you intend to ship, not just AMD's reference image. An x86 embedded SoC also moves a team used to Arm device trees toward ACPI-based enumeration, a real BSP and skills consideration to plan for and budget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Google's LiteRT.js pushes inference into the browser
&lt;/h2&gt;

&lt;p&gt;Google has released &lt;a href="https://developers.googleblog.com/litertjs-googles-high-performance-web-ai-inference/" rel="noopener noreferrer"&gt;LiteRT.js&lt;/a&gt;, a JavaScript build of its LiteRT on-device runtime, the runtime formerly known as TensorFlow Lite, that runs &lt;code&gt;.tflite&lt;/code&gt; models directly in the browser. It brings the LiteRT C++ runtime to the web through WebAssembly, using XNNPACK on the CPU, ML Drift over WebGPU for the GPU, and an experimental WebNN path for neural accelerators. Google reports up to three times the performance of previous web runtimes on vision and audio models, and much larger gains over its own CPU path when WebGPU is available.&lt;/p&gt;

&lt;p&gt;For an embedded audience this matters wherever the product's interface is a browser: kiosks, industrial HMIs, medical and retail front ends, and any device that already ships a web UI. Running inference locally in that interface removes the round trip to a server, which means lower latency, no per-inference cloud cost, and data that stays on the device.&lt;/p&gt;

&lt;p&gt;The trade-off is the sandbox. WebGPU gives the browser real GPU compute, but through a portable abstraction, not the native driver and delegate control you get from LiteRT on the device itself. Memory is bounded by the browser, the NPU path through WebNN is still experimental and limited to some browsers, and you give up the deterministic, hardware-specific tuning a native runtime allows. What you gain is portability: one build runs across whatever GPU the host exposes, with no per-target driver work.&lt;/p&gt;

&lt;p&gt;The practical read is that browser inference is now fast enough to be a real option for on-device features in an embedded web UI, not only a demonstration. Where you need full control of the accelerator and predictable latency, the native runtime remains the right tool; where portability and privacy matter more, LiteRT.js is worth evaluating. A companion preview, LiteRT-LM.js, extends the idea to language models in the browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to use it
&lt;/h3&gt;

&lt;p&gt;Getting a model running in the browser is a short path. Install the runtime, load the Wasm, then compile a &lt;code&gt;.tflite&lt;/code&gt; model against a backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;raghu@techveda.org:~$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @litertjs/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loadLiteRt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loadAndCompile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@litertjs/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadLiteRt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cdn.jsdelivr.net/npm/@litertjs/core/wasm/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadAndCompile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/models/vision.tflite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;accelerator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webgpu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// 'webgpu' | 'webnn' | 'wasm'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Operations unsupported on the chosen backend fall back to the CPU automatically, so the same code runs where WebGPU is unavailable. An existing &lt;a href="https://developers.google.com/edge/litert/web" rel="noopener noreferrer"&gt;TensorFlow.js pipeline&lt;/a&gt; can keep its pre- and post-processing and swap only the model, using the &lt;code&gt;@litertjs/tfjs-interop&lt;/code&gt; package. For an embedded HMI, that means one build serves whatever GPU the device's browser exposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.kernel.org/process/generated-content.html" rel="noopener noreferrer"&gt;Kernel Guidelines for Tool-Generated Content — docs.kernel.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.kernel.org/process/coding-assistants.html" rel="noopener noreferrer"&gt;AI Coding Assistants — docs.kernel.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lwn.net/Articles/1046552/" rel="noopener noreferrer"&gt;Documentation: Provide guidelines for tool-generated content (v3) — LWN.net&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://lwn.net/Articles/1082717/" rel="noopener noreferrer"&gt;Sched-ext: enqueue() for sub-schedulers and proxy-execution support — LWN.net&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.kernel.org/scheduler/sched-ext.html" rel="noopener noreferrer"&gt;Extensible Scheduler Class (sched_ext) — docs.kernel.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techveda.live/2025/09/16/the-sched_ext-revolution-the-future-of-cpu-scheduling-in-linux/" rel="noopener noreferrer"&gt;The sched_ext Revolution: The Future of CPU Scheduling in Linux — TECH VEDA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techveda.live/2025/09/16/the-sched_ext-architecture/" rel="noopener noreferrer"&gt;The sched_ext Architecture — TECH VEDA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techveda.live/2025/09/17/meet-the-sched_ext-ecosystem/" rel="noopener noreferrer"&gt;Meet the sched_ext Ecosystem — TECH VEDA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://newsroom.amd.com/news/aai-2026-ryzen-ai-embedded-x100/" rel="noopener noreferrer"&gt;AMD Ryzen AI Embedded X100 Series — AMD Newsroom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://newsroom.amd.com/news/aai-2026-kria-robotics-dev-platform/" rel="noopener noreferrer"&gt;AMD Kria AI Robotics Developer Platform — AMD Newsroom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.amd.com/en/products/embedded/ryzen-ai/x100-series.html" rel="noopener noreferrer"&gt;AMD Ryzen AI Embedded X100 Series — product page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.googleblog.com/litertjs-googles-high-performance-web-ai-inference/" rel="noopener noreferrer"&gt;LiteRT.js, Google's high-performance web AI inference — Google Developers Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/edge/litert/web" rel="noopener noreferrer"&gt;LiteRT for Web with LiteRT.js — Google AI Edge documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.techveda.live/2026/08/06/kernel-ai-patch-guidelines/" rel="noopener noreferrer"&gt;techveda.live&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;— Raghu Bharadwaj&lt;/p&gt;

</description>
      <category>linux</category>
      <category>kernel</category>
      <category>embedded</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Mindset Behind Hard Debugging</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Thu, 06 Aug 2026 06:07:53 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/the-mindset-behind-hard-debugging-1bka</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/the-mindset-behind-hard-debugging-1bka</guid>
      <description>&lt;p&gt;Hard debugging is rarely defeated by a lack of tools. It is defeated by three quiet habits: assuming the fault is where the symptom appears, clinging to the first explanation, and hoping a tool will do the thinking. A difficult fault is usually lost to those habits before you read a line of code. The engineers who resolve hard faults are the ones who notice these defaults and replace them with a patient, evidence-first mindset.&lt;/p&gt;

&lt;p&gt;Most hard bugs are lost before we touch them, in the attitude we bring to the session.&lt;/p&gt;

&lt;p&gt;When something breaks, the average person rushes in with three quiet habits: they assume the fault lives exactly where it shows up, they cling to the first explanation their mind offers, and they hope a tool or a smarter person will tell them what to do next. Those habits feel natural, but on hard faults they are exactly what keep us stuck.&lt;/p&gt;

&lt;p&gt;Put two engineers on the same failing board. One finds a way through in an afternoon; the other is still going three days later. The difference is rarely raw intelligence or how many commands they know. It is the mental posture each brings to the work before the first step. Handling a hard debug session is less about knowing every tool and more about managing your own assumptions, reactions, and impatience.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A tough problem is usually lost in your mindset before it is lost in your methods.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Habit one: starting too narrow
&lt;/h2&gt;

&lt;p&gt;The first habit is to fix on the most visible symptom and refuse to look anywhere else. Something breaks, so we stare at the last thing we changed, and we return to it because it is familiar and close at hand. When the answer is not there, we look harder in the same place instead of stepping back.&lt;/p&gt;

&lt;p&gt;Here is what that looks like on real hardware. A device keeps dropping off the bus. You are a kernel person, so you open the driver and read it, carefully, for three days: the probe path, the error handling, the power-management callbacks. Every line is correct, and the device still fails. The fault was a layer below the entire time, in a marginal connector and a power rail that sagged under load. Reading C could not localise it, because the problem was not written in C.&lt;/p&gt;

&lt;p&gt;The mindset shift is to start wide. A real system is a stack of layers: application, kernel, driver, board, power, and the signals on the wires. What you see on the surface is often just where a deeper fault finally shows itself. This is why David Agans opens &lt;em&gt;Debugging: The 9 Indispensable Rules&lt;/em&gt; with the rule that comes before all the others: "Understand the System." If your model of the system stops at the software, the layer that owns the fault is not in your model, and you cannot search a layer your model does not contain. Engineers who handle hard sessions well resist the pull toward the layer they know best; they pause, sketch the whole picture, and choose where to look.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not confuse where it hurts with where it started.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Habit two: trusting the first explanation
&lt;/h2&gt;

&lt;p&gt;The second habit is to treat your first explanation as the truth. Within seconds, the mind produces a story: it must be this driver, this flag, this commit. From that moment it collects only the facts that support the story and quietly ignores the rest. You feel as though you are analysing, when you are often defending a guess.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The first principle is that you must not fool yourself and you are the easiest person to fool." - Richard Feynman&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The mindset shift is humility. Treat the first theory as a possibility, not a verdict, and read all of the evidence the system already gave you (the full message, the log, the oops, the register that held the bad value) before you decide what you believe. Agans states this as a rule of its own, "Quit Thinking and Look": observe the actual behaviour before you explain it. And when you do change something, change one thing at a time, so each result answers exactly one question; change several at once and you can no longer tell which change mattered.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Strong debuggers care more about being right in the end than feeling right in the moment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Habit three: outsourcing the thinking
&lt;/h2&gt;

&lt;p&gt;The third habit is modern and seductive: believing a tool can do the thinking for us. Stuck, we search, paste, prompt, or ask around, and treat the reply as a substitute for understanding. An assistant answers inside whichever layer you named; it never held a model of your board, your load, or your timing, so it cannot tell you that the layer you asked about was the wrong place to look. The reply may be fluent, fast, and confident, and a fluent explanation is still not a tested one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The most effective debugging tool is still careful thought, coupled with judiciously placed print statements." - Brian Kernighan&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tools are useful, sometimes indispensable, but they are at their best when they test a question you have already framed. A print statement, a trace, an oscilloscope, or an AI prompt can help you inspect; it cannot decide what deserves attention, which pattern matters, or which assumption to challenge next. That part remains yours.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A good tool answers questions. A good mindset decides which questions are worth asking.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The mindset that handles hard faults
&lt;/h2&gt;

&lt;p&gt;These habits are not signs of a weak engineer. They are the natural defaults of any fast mind under pressure, and hard debugging is the practice of noticing those defaults and replacing them with better ones: patience instead of haste, curiosity instead of ego, observation instead of premature certainty. On the next hard fault, run a small, repeatable routine.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pause before acting and name the layers the failure passes through: application, kernel, driver, board, power, and signal.&lt;/li&gt;
&lt;li&gt;Read everything the system is already telling you (the full error, the log, the oops) before you form a theory.&lt;/li&gt;
&lt;li&gt;Name your current hypothesis about which layer owns the fault, but stay willing to discard it.&lt;/li&gt;
&lt;li&gt;Change one thing at a time, and ask one clear question with each change.&lt;/li&gt;
&lt;li&gt;Reach for the one instrument, or the one AI prompt, that tests that single hypothesis, and treat its answer as evidence about one layer, not a verdict on the whole system.&lt;/li&gt;
&lt;li&gt;Let evidence, not relief, tell you the fault is solved. A disappearing symptom is not the same as a fixed cause.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools will keep improving, and an assistant will keep producing quicker and more plausible answers. None of that removes the work at the centre of every hard session, which is human judgement: deciding what to believe, what to doubt, and what to test next. That judgement is what turns a chaotic failure into a manageable investigation, and it is the habit we build deliberately in TECH VEDA training: understand the system first, read the evidence before you commit to a theory, and use tools only to confirm a conclusion you have already reasoned your way toward. It is also what makes an engineer trustworthy when the easy answers fail.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;- Raghu Bharadwaj&lt;/em&gt;&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>embedded</category>
      <category>linux</category>
      <category>career</category>
    </item>
    <item>
      <title>The Kernel Maintainer Bottleneck and What It Means for Upstreaming</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Thu, 06 Aug 2026 04:18:56 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/the-kernel-maintainer-bottleneck-and-what-it-means-for-upstreaming-53oh</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/the-kernel-maintainer-bottleneck-and-what-it-means-for-upstreaming-53oh</guid>
      <description>&lt;p&gt;Contributions to the Linux kernel are at record highs, but the number of people who review and merge those contributions has not grown at the same rate. This is the kernel maintainer bottleneck: the constraint has moved from writing code to getting it reviewed and accepted. For embedded teams sending drivers and board support upstream, it means longer lead times and a real advantage for patches that are easy to review.&lt;/p&gt;

&lt;p&gt;If you have sent a patch to a kernel subsystem and watched it sit on the mailing list for weeks, you have met the kernel maintainer bottleneck first hand. The problem is usually not that your code is wrong. It is that the small number of people who can review and merge it are handling more work than ever. Kernel development in 2026 has plenty of hands writing code. What it has less of is time to review that code and move it toward the mainline.&lt;/p&gt;

&lt;p&gt;This is not a complaint about individuals. It is a structural feature of how the kernel is built, and it is now discussed openly by the people who run the project. Understanding it helps you plan upstreaming work realistically instead of being surprised by it.&lt;/p&gt;

&lt;h2&gt;
  
  
  More code, more contributors, every year
&lt;/h2&gt;

&lt;p&gt;By raw activity, the kernel community looks healthy and is still growing. The 6.18 release, which closed the last full development cycle of 2025, brought in 13,710 commits from 2,134 developers. That developer count is the highest in the kernel's history. The release also drew 333 first-time contributors, just short of the record 335 set a year earlier in 6.12.&lt;/p&gt;

&lt;p&gt;Across the full year covered by releases 6.13 through 6.18, the kernel absorbed 80,035 non-merge changesets from 5,275 developers working for 372 known employers. Greg Kroah-Hartman has noted that every single release now features the work of at least 200 first-time contributors. The supply of people who want to write kernel code is not the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the kernel maintainer bottleneck actually sits
&lt;/h2&gt;

&lt;p&gt;Writing a patch is the part of the process that scales with the number of contributors. Reviewing and merging that patch does not scale the same way, because it depends on a much smaller and more stable group of people.&lt;/p&gt;

&lt;p&gt;The tags recorded on merged commits show this. In 6.18, 53.6% of commits carried a Reviewed-by tag and only 9.0% carried a Tested-by tag, both typical figures for recent releases. The most active reviewers are close to the same names release after release; as the kernel's own statistics put it, the community's most diligent reviewers are seemingly in it for the long term. On the merge side, just over half of all patches reaching the mainline pass through the hands of maintainers employed by only five companies: Meta and Google, Intel and AMD, and Red Hat. When a handful of trusted people gate most of the flow, their available hours determine how fast everyone else's work moves.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Key insight:&lt;/strong&gt; The limit on kernel throughput is not how much code gets written. It is how much code a small, relatively fixed set of reviewers and maintainers can examine and accept.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A warning from 2018 that reads differently now
&lt;/h2&gt;

&lt;p&gt;This concern is not new. In 2018 Daniel Vetter, a longtime graphics maintainer, studied how often maintainers commit their own patches and used that as a proxy for maintainer capacity. He found that the number was falling relative to the kernel's growth, and that the community was not training new maintainers fast enough to keep up. His extrapolation was blunt: &lt;em&gt;"around the year 2025 large numbers of kernel maintainers will do nothing else than be the bottleneck, preventing everyone else from getting their work merged and not contributing anything of their own."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;He also pointed to a double standard that still exists: ordinary contributors must get their patches reviewed, while maintainers can commit their own code with no recorded review. His darker forecast, that the community would implode under its own bureaucratic weight, did not come true. Contributions kept climbing to record levels. But the underlying concern he raised has moved from a contrarian blog post to a mainstream topic that the project now plans around.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Key insight:&lt;/strong&gt; The kernel did not collapse under maintainer load. Instead, the load became a first-class process problem that the project actively manages, rather than an edge worry that gets dismissed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Burnout, succession, and more patches than ever
&lt;/h2&gt;

&lt;p&gt;The human side of this is now discussed directly at the yearly Maintainers Summit. At the 2023 summit, Ted Ts'o observed that maintainers end up absorbing every task nobody else wants to take on: patch review, release engineering, testing, and responding to security reports. Those expectations have only grown over time.&lt;/p&gt;

&lt;p&gt;The 2025 Maintainers Summit, held in Tokyo on 10 December, devoted a full session to continuity and succession planning. There are now provisions so that no single person is a point of failure: several people can commit to Linus Torvalds's repository, and the stable tree has similar redundancy. If a smooth handover ever became impossible, the plan is for the attendees of the most recent summit to convene and decide the path forward. Torvalds, for his part, has signed a new contract with the Linux Foundation and does not plan to step back soon.&lt;/p&gt;

&lt;p&gt;Two recent developments show why the process layer, not the code, is often the part under strain. The bcachefs filesystem was removed from the mainline kernel in 2025 after repeated disagreements over the development process, an episode one participant described as a "perfect storm." And the same 2025 summit opened a discussion toward a policy for machine-learning tools in kernel development, driven in part by a simple worry: tools that generate patches faster add review load to the same limited group of people.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the kernel maintainer bottleneck means for your team
&lt;/h2&gt;

&lt;p&gt;If your work involves sending drivers, board support, or fixes upstream, the bottleneck has direct, practical consequences. A few habits help you work with it rather than against it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Budget real lead time for upstreaming.&lt;/strong&gt; A non-trivial driver or board-support series can take several release cycles to land, not one. Plan product schedules around that reality instead of an optimistic single-cycle merge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make patches cheap to review.&lt;/strong&gt; Small, well-split series, clear commit messages, and included tests move faster because each one costs a maintainer less time and attention.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Become a reviewer, not only a submitter.&lt;/strong&gt; Review capacity is the scarce resource. A team that helps review other people's work in a subsystem builds the trust and goodwill that gets its own patches merged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefer subsystems with active, multi-person maintainership.&lt;/strong&gt; Where you have a design choice, a well-staffed subsystem is less likely to stall on one person's availability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep an out-of-tree plan.&lt;/strong&gt; If a series will not land before you ship, know the cost of carrying it as a downstream patch and have a concrete plan to upstream it later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are exactly the working habits we focus on in our &lt;a href="https://www.techveda.live/linux-kernel-infrastructure/" rel="noopener noreferrer"&gt;Linux Kernel Infrastructure training&lt;/a&gt;, where writing reviewable, mainline-ready code is treated as a core skill rather than an afterthought.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Key insight:&lt;/strong&gt; For an embedded team, the useful response to the bottleneck is to lower the review cost of your own contributions and to help carry the review load, not to wait for the constraint to disappear.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Kernel contributions are at record highs; review and merge capacity is the real constraint.&lt;/li&gt;
&lt;li&gt;Only about 54% of merged commits carry a recorded review, and just over half of all patches pass through maintainers at five companies.&lt;/li&gt;
&lt;li&gt;Daniel Vetter predicted a maintainer bottleneck around 2025; the collapse he feared did not happen, but the concern is now a mainstream process topic.&lt;/li&gt;
&lt;li&gt;Burnout, succession planning, and a growing volume of machine-generated patches are all active concerns for the people who run the project.&lt;/li&gt;
&lt;li&gt;Teams that write reviewable patches, help review, and budget for longer upstreaming timelines get their code merged with less friction.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is the kernel maintainer bottleneck?&lt;/strong&gt;&lt;br&gt;
It is the gap between how much code is submitted to the Linux kernel and how much a relatively small group of reviewers and maintainers can review and merge. Writing patches scales with the number of contributors; review and acceptance do not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is the Linux kernel running out of maintainers?&lt;/strong&gt;&lt;br&gt;
No. Every release still draws record numbers of contributors, including at least 200 first-time contributors. The narrower concern is that review and merge work is concentrated in a small, stable group, and training new maintainers has not kept pace with the growth in contributions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long does it take to get a patch merged upstream?&lt;/strong&gt;&lt;br&gt;
It varies by subsystem, but a non-trivial driver or board-support series often takes several release cycles rather than one. Well-split, clearly described, and tested patches move faster because they cost reviewers less time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can an embedded team reduce the impact of the bottleneck?&lt;/strong&gt;&lt;br&gt;
Budget lead time for upstreaming, make patches small and easy to review, contribute review effort back to the subsystem, prefer subsystems with active multi-person maintainership, and keep a plan for carrying code out-of-tree if it will not land before you ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Jonathan Corbet, &lt;a href="https://lwn.net/Articles/1046966/" rel="noopener noreferrer"&gt;"Some 6.18 development statistics"&lt;/a&gt;, LWN.net, 1 December 2025.&lt;/li&gt;
&lt;li&gt;Daniel Vetter, &lt;a href="https://lwn.net/Articles/752563/" rel="noopener noreferrer"&gt;"Linux Kernel Maintainer Statistics"&lt;/a&gt; (LWN summary), LWN.net, April 2018.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://lwn.net/Articles/1049982/" rel="noopener noreferrer"&gt;"The 2025 Maintainers Summit"&lt;/a&gt;, LWN.net, December 2025.&lt;/li&gt;
&lt;li&gt;Jonathan Corbet, &lt;a href="https://lwn.net/Articles/1050179/" rel="noopener noreferrer"&gt;"2025 Maintainers Summit development process discussions"&lt;/a&gt;, LWN.net, 16 December 2025.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://lwn.net/Articles/952034/" rel="noopener noreferrer"&gt;"Reducing kernel-maintainer burnout"&lt;/a&gt;, LWN.net, 2023 Maintainers Summit coverage.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://www.techveda.live/2026/08/06/kernel-maintainer-bottleneck/" rel="noopener noreferrer"&gt;TECH VEDA blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>kernel</category>
      <category>embedded</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Yocto vs Buildroot: Choosing a Build System for Your Product</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Wed, 05 Aug 2026 11:29:48 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/yocto-vs-buildroot-choosing-a-build-system-for-your-product-4e1b</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/yocto-vs-buildroot-choosing-a-build-system-for-your-product-4e1b</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;For most products you plan to ship, maintain, and update across several years and hardware variants, the Yocto Project is the stronger choice, because its layer model, shared-state cache, generated SDK, and on-target package feeds are built for long-lived maintenance. Buildroot is the better choice when the system is small and fixed, the team is small, the schedule is short, and you will replace the whole image to update it. The trade-off is direct: Yocto asks for a steeper learning curve and heavier build infrastructure in exchange for long-term maintainability; Buildroot gives you simplicity and speed now, and asks for more effort as the product grows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every embedded Linux product starts with one decision that shapes years of work: which build system produces the root filesystem. In practice the shortlist is two names. &lt;strong&gt;Yocto vs Buildroot&lt;/strong&gt; is the choice almost every team makes, and it is easy to make it for the wrong reason, such as familiarity or a first-week demonstration, rather than the reasons that matter over the product's life.&lt;/p&gt;

&lt;p&gt;This article treats it as an architecture decision: when it arises, both options on their merits, a recommendation for the common case, and the conditions under which the other option wins. It matters because the cost of a build system shows up in maintenance, not in the first build.&lt;/p&gt;

&lt;h2&gt;
  
  
  The context
&lt;/h2&gt;

&lt;p&gt;The decision arises at the start of a new product, or when an existing product outgrows a vendor's reference image and you decide to own the root filesystem yourself. A few forces are in play, and they usually matter more than any single technical feature.&lt;/p&gt;

&lt;p&gt;The first is product lifetime and update obligation: a device you will support and security-patch for five to ten years has different needs from a demonstration unit. The second is the number of variants, since one board and one image is a different problem from a family of products that share most of their software. The third is team size and skills, because a build system you cannot staff is a risk regardless of its features. The fourth is your chosen update strategy, since delivering fixes as packages differs from replacing the entire image. Regulation such as the EU Cyber Resilience Act now adds weight to the security and update forces for connected products.&lt;/p&gt;

&lt;h2&gt;
  
  
  The options: Yocto vs Buildroot
&lt;/h2&gt;

&lt;p&gt;Both tools are mature and actively maintained; neither is a poor choice. They differ in what they optimise for.&lt;/p&gt;

&lt;h3&gt;
  
  
  Buildroot
&lt;/h3&gt;

&lt;p&gt;Buildroot is built around simplicity. It uses the same &lt;code&gt;Kconfig&lt;/code&gt; and &lt;code&gt;make&lt;/code&gt; workflow as the kernel itself, so a kernel or embedded engineer can read a configuration and understand the whole system quickly. It integrates more than 2000 packages and produces a root filesystem image and a toolchain from a single configuration. The current stable series is 2026.05.1 (released 15 July 2026), and the long-term support series is 2025.02.x, maintained until March 2028. Since the 2025.02 release, Buildroot's LTS branches are supported for three years.&lt;/p&gt;

&lt;p&gt;A defining design choice is that Buildroot does not include a runtime package manager and does not generate binary packages by default. The project documents this deliberately: safely removing a package and its reverse dependencies at runtime is hard, so Buildroot treats the image as a whole, and a configuration change that affects dependencies is handled by a clean rebuild rather than an in-place update.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Strengths:&lt;/em&gt; a short path from zero to a working image; a configuration that is easy to read and reason about; fast to learn; small, predictable output. &lt;em&gt;Limits:&lt;/em&gt; no on-target package management; configuration changes often mean full rebuilds; large multi-variant product lines and complex, layered customisation are harder to express than in Yocto.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Yocto Project
&lt;/h3&gt;

&lt;p&gt;The Yocto Project is built around flexibility and long-term maintenance. It uses the BitBake build engine with metadata organised as layers (the reference distribution is Poky, on top of OpenEmbedded). Software is described by recipes, board and vendor support arrives as layers you add rather than patches you carry, and a shared-state cache (sstate) makes later builds incremental. Yocto can generate a cross-development SDK for application teams and can build on-target package feeds in rpm, deb, or ipk format, which makes package-based field updates possible. The current LTS release is Wrynose (6.0), supported until April 2030 (BitBake 2.18); the previous LTS, Scarthgap (5.0), is supported until April 2028. Yocto designates an LTS every two years, each supported for four.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Strengths:&lt;/em&gt; the layer model maps directly onto vendor BSPs and product variants; sstate keeps incremental builds practical on large projects; SDK generation and package feeds support long-lived maintenance and field updates; the ecosystem and commercial support are large. &lt;em&gt;Limits:&lt;/em&gt; a steeper learning curve; more moving parts to debug; a larger disk, memory, and build-time footprint, especially for the first build and CI.&lt;/p&gt;

&lt;p&gt;The difference shows in the first build; the commands below are illustrative, not a tutorial.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Buildroot: one configuration, one image&lt;/span&gt;
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;make qemu_arm_vexpress_defconfig
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;make menuconfig
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;make

&lt;span class="c"&gt;# Yocto: environment, layers, then a BitBake target&lt;/span&gt;
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;source &lt;/span&gt;oe-init-build-env
raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;bitbake core-image-minimal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The decision
&lt;/h2&gt;

&lt;p&gt;For the common product case, choose the Yocto Project. If you will ship in volume, support for years, patch for security, and produce several hardware or feature variants, the layer model and package feeds pay back the steeper learning curve. Vendor board support that arrives as a Yocto layer keeps your changes separate from upstream, which is what a long maintenance life needs. The same reasoning runs through our note on &lt;a href="https://www.techveda.live/2026/08/02/mainline-friendly-products/" rel="noopener noreferrer"&gt;architecting mainline-friendly products&lt;/a&gt;: keep your customisation isolated from the code you do not own.&lt;/p&gt;

&lt;p&gt;Choose Buildroot when the system is simple and the constraints point the other way. It is the right decision for a single fixed-function image with few variants, a small team that needs to move quickly, a tight schedule where Yocto's learning curve is a real risk, and prototypes or internal tools. It is also a sound choice for deeply constrained devices that you will always update by replacing the whole image and never need on-target packages. In those situations Buildroot is not a compromise; it is the more honest fit for the requirement.&lt;/p&gt;

&lt;p&gt;The common mistake is choosing for the wrong reason: do not pick Buildroot only because it demonstrates faster, or Yocto only because a large vendor uses it. Match the tool to the product's lifetime, variant count, update strategy, and the team you have.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consequences
&lt;/h2&gt;

&lt;p&gt;Whatever you choose, you accept long-term consequences. Naming them in advance is the point of a deliberate decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maintenance and updates.&lt;/strong&gt; With Yocto, vendor and board changes live in layers and security fixes flow through recipe updates and package feeds. With Buildroot, customisation tends to live as local configuration and patches, and updates usually mean building and deploying a new image. Yocto matches a package-based update strategy; Buildroot matches whole-image replacement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security backporting.&lt;/strong&gt; Both projects run LTS branches, so both give you a maintained base. Yocto's layer separation makes it easier to track which vendor component a fix belongs to, which helps when you must answer for a specific CVE on a specific board.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hiring and onboarding.&lt;/strong&gt; Buildroot is quicker to learn, so a new engineer becomes productive sooner. Yocto skills are scarcer and take longer to build, but they are more valued in the market and let a team take on larger products.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build infrastructure.&lt;/strong&gt; Yocto needs more disk, memory, and continuous-integration time, and the first build is long; sstate reduces the cost of later builds but not the initial investment. Buildroot's footprint is smaller and more predictable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migration.&lt;/strong&gt; Reversing the Yocto vs Buildroot choice later is expensive, because recipes and Kconfig customisations do not translate directly. That is the strongest argument for choosing carefully now rather than switching under pressure. Boot time and image size, it is worth noting, are mostly a function of what you put in the image, not which tool assembled it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Yocto vs Buildroot is an architecture decision about the product's whole life, not a first-week convenience.&lt;/li&gt;
&lt;li&gt;Default to the Yocto Project for shippable products with multi-year support, multiple variants, vendor BSPs, or package-based updates.&lt;/li&gt;
&lt;li&gt;Choose Buildroot for simple, fixed-function systems, small teams, tight schedules, prototypes, and whole-image update strategies.&lt;/li&gt;
&lt;li&gt;Buildroot by design has no runtime package manager; Yocto can build package feeds and an SDK.&lt;/li&gt;
&lt;li&gt;Migrating between the two later is costly, so decide on the merits now.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is Yocto always better than Buildroot?&lt;/strong&gt;&lt;br&gt;
No. Yocto is the stronger default for long-lived products with multiple variants and package-based updates, but Buildroot is the better fit for simple, fixed-function systems, small teams, tight schedules, and whole-image update strategies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can Buildroot update a device with packages in the field?&lt;/strong&gt;&lt;br&gt;
Not by default. Buildroot does not include a runtime package manager and does not generate binary packages, so the standard update path is to build and deploy a new root filesystem image. If you need on-target package updates, Yocto's rpm, deb, or ipk feeds support that model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which current releases should I target?&lt;/strong&gt;&lt;br&gt;
On Buildroot, the long-term support series 2025.02.x is maintained until March 2028, with 2026.05.1 as the current stable series. On Yocto, the current LTS is Wrynose (6.0), supported until April 2030, and Scarthgap (5.0) is supported until April 2028.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the build system decide boot time and image size?&lt;/strong&gt;&lt;br&gt;
Mostly no. Boot time and image size are determined by what you include in the image and how you configure it. Both Buildroot and Yocto can produce a small, fast-booting system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://buildroot.org/downloads/manual/manual.html" rel="noopener noreferrer"&gt;The Buildroot user manual&lt;/a&gt; — configuration model, and why Buildroot does not generate binary packages.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://buildroot.org/lts.html" rel="noopener noreferrer"&gt;Buildroot LTS&lt;/a&gt; and the &lt;a href="https://buildroot.org/download.html" rel="noopener noreferrer"&gt;download page&lt;/a&gt; — current stable and long-term support releases.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.yoctoproject.org/" rel="noopener noreferrer"&gt;Yocto Project documentation&lt;/a&gt; and the &lt;a href="https://wiki.yoctoproject.org/wiki/Releases" rel="noopener noreferrer"&gt;release table&lt;/a&gt; — layers, BitBake, sstate, SDK, and LTS dates.&lt;/li&gt;
&lt;li&gt;TECH VEDA training: &lt;a href="https://www.techveda.live/embedded-linux-yocto/" rel="noopener noreferrer"&gt;Embedded Linux on EdgeAI platforms&lt;/a&gt; — hands-on work with both Buildroot and Yocto, from configuration to BSPs.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.techveda.live/2026/08/05/yocto-vs-buildroot-choosing-a-build-system-for-your-product/" rel="noopener noreferrer"&gt;TECH VEDA&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>embedded</category>
      <category>yocto</category>
      <category>buildroot</category>
    </item>
    <item>
      <title>Speculative Decoding: Faster On-Device LLMs</title>
      <dc:creator>Raghu Bharadwaj</dc:creator>
      <pubDate>Wed, 05 Aug 2026 02:00:45 +0000</pubDate>
      <link>https://dev.to/raghu_bharadwaj_404e60eb0c/speculative-decoding-faster-on-device-llms-mh3</link>
      <guid>https://dev.to/raghu_bharadwaj_404e60eb0c/speculative-decoding-faster-on-device-llms-mh3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Speculative decoding makes a large language model generate text faster on a constrained device without changing what it produces. A small draft model guesses several tokens ahead, and the large model checks all of those guesses in a single pass. Because single-stream decoding is limited by memory bandwidth rather than by arithmetic, checking many tokens in one memory read is close to free, which is why the technique helps most on memory-bound edge hardware.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Running a language model on a device is usually slower than people expect, and not because the processor is short of arithmetic power. On a phone or single-board computer, generating text one token at a time is limited by how fast the model weights move from memory into the compute units. &lt;strong&gt;Speculative decoding&lt;/strong&gt; is a way to raise that ceiling: it produces the same output as ordinary decoding but pays the memory cost less often.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why on-device decoding is slow
&lt;/h2&gt;

&lt;p&gt;An autoregressive model generates one token per forward pass. At batch size one, producing that single token means reading every weight in the model from memory, multiplying it by a small activation vector, and discarding it. The arithmetic per weight is tiny, so the processor spends most of its time waiting for data. In roofline terms, &lt;strong&gt;single-token decoding is memory-bandwidth bound, not compute bound&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The numbers make this concrete. A Jetson Orin Nano 8GB reaches about 68 GB/s over its LPDDR5 bus. A 7-billion-parameter model stored at 4 bits per weight is roughly 4 GB. Reading 4 GB at 68 GB/s takes about 59 milliseconds, so the memory system alone caps decoding at under 20 tokens per second before a single useful multiply is counted. Faster arithmetic units do not move that ceiling, because the ceiling is set by data movement. This is the constraint the technique is designed to attack.&lt;/p&gt;

&lt;h2&gt;
  
  
  The key idea behind speculative decoding
&lt;/h2&gt;

&lt;p&gt;Much of the text a large model produces is easy to predict. Function words, common phrasing, and the obvious continuation of a sentence do not need the full model to be guessed correctly, so a much smaller model can propose them quickly. The large model is then used only to &lt;em&gt;verify&lt;/em&gt; the proposals, not to generate each token from scratch.&lt;/p&gt;

&lt;p&gt;Verification is the important part. &lt;strong&gt;Speculative decoding is exact, not approximate.&lt;/strong&gt; The large model runs once over the whole batch of proposals, and a carefully chosen acceptance rule keeps only the prefix that is consistent with what the large model itself would have sampled. The rule is built so that the final output has the same probability distribution as ordinary decoding from the large model. The text you get is statistically identical to running the large model alone; only the speed changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works, step by step
&lt;/h2&gt;

&lt;p&gt;One decoding step looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The small draft model generates a short run of candidate tokens, for example eight. This is cheap because the model is small.&lt;/li&gt;
&lt;li&gt;The large target model runs a single forward pass over all eight positions at once, so its weights are read from memory only once for the whole group.&lt;/li&gt;
&lt;li&gt;The candidates are compared against what the target model would accept, and tokens are kept up to the first point where draft and target disagree.&lt;/li&gt;
&lt;li&gt;At the disagreement point the target model's own prediction is used, so at least one correct token is always produced per step, and the process repeats.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the draft is good, several tokens are accepted per step, and the device produces multiple tokens for the price of one target-model memory read. If it is often wrong, fewer are accepted and the benefit shrinks toward ordinary decoding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the accepted tokens are almost free
&lt;/h2&gt;

&lt;p&gt;The saving comes back to the memory-bandwidth wall. Reading the target model's weights is the expensive step, and that read happens once per forward pass regardless of how many token positions the pass covers. Processing eight positions instead of one turns a set of tiny vector multiplies into slightly larger matrix multiplies, and on memory-bound hardware there is spare arithmetic capacity to absorb that extra work. So &lt;strong&gt;the additional positions cost almost nothing beyond the memory read you were already paying for&lt;/strong&gt;. Every proposed token that survives verification is one you did not fetch the weights again to produce.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the numbers look like
&lt;/h2&gt;

&lt;p&gt;The original demonstration reported a 2x to 3x wall-clock speed-up on a large encoder-decoder model, with output identical to the standard implementation. The exact figure on your device depends above all on the acceptance rate: the fraction of drafted tokens the target model keeps. A high acceptance rate on predictable text yields larger speed-ups; a low rate on hard, high-entropy text yields little.&lt;/p&gt;

&lt;p&gt;Production inference engines now implement this directly. In llama.cpp, you enable it by passing a small draft model alongside the target model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;raghu@techveda.org:~&lt;span class="nv"&gt;$ &lt;/span&gt;./llama-cli &lt;span class="nt"&gt;-m&lt;/span&gt; qwen2.5-7b-q4.gguf &lt;span class="nt"&gt;-md&lt;/span&gt; qwen2.5-0.5b-q4.gguf &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Explain what a spinlock is"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;-m&lt;/code&gt; is the target and &lt;code&gt;-md&lt;/code&gt; (also &lt;code&gt;--model-draft&lt;/code&gt;) is the draft model. The number of tokens proposed per step is tunable with a separate draft-length flag. No retraining or architecture change is required; the draft only needs to share the target's vocabulary so their tokens line up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it breaks down
&lt;/h2&gt;

&lt;p&gt;It is not a universal win. Several conditions can cancel the benefit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Low acceptance rate.&lt;/strong&gt; If the draft model rarely agrees with the target, the extra draft and verification work can make generation slower than plain decoding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory pressure.&lt;/strong&gt; The draft model must stay resident in DRAM alongside the target model and its key-value cache, which may be exactly the footprint a constrained board cannot spare.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared-memory contention.&lt;/strong&gt; On a unified-memory SoC the draft and target share the same processors and LPDDR bus, so a draft that is too large eats into the bandwidth you were trying to save.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute-bound regimes.&lt;/strong&gt; If you are already serving a large batch, or running a small model on a fast accelerator, the target pass is compute bound rather than memory bound, and the "free" verification is no longer free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vocabulary mismatch.&lt;/strong&gt; The draft and target must use compatible tokenizers, limiting which model pairs you can combine.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What this means for embedded and kernel engineers
&lt;/h2&gt;

&lt;p&gt;The lesson generalizes beyond language models. When you profile an on-device inference workload and find the accelerator idle while memory traffic is saturated, the bottleneck is data movement, and the fix is to move less data or to reuse each transfer for more work. This method reuses a single weight read to settle several tokens; the same reasoning guides weight quantization, operator fusion, and how you place tensors across a shared memory hierarchy. On single-batch edge inference, the common case, memory bandwidth is usually the number to design around. These foundations — where the bytes move, and how the memory subsystem and scheduler behave under that load — are comprehensively covered in our &lt;a href="https://www.techveda.live/embedded-linux-yocto/" rel="noopener noreferrer"&gt;training programs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Single-stream, on-device decoding is limited by memory bandwidth, not by arithmetic throughput.&lt;/li&gt;
&lt;li&gt;Speculative decoding uses a small draft model to propose tokens and the large model to verify them in one pass, producing identical output to ordinary decoding.&lt;/li&gt;
&lt;li&gt;Accepted tokens are nearly free because the target model's weights are read from memory once per verification pass.&lt;/li&gt;
&lt;li&gt;Reported speed-ups are around 2x to 3x, but the real figure depends on the draft model's acceptance rate.&lt;/li&gt;
&lt;li&gt;The technique can lose its advantage under memory pressure, low acceptance, shared-bus contention, or compute-bound serving.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does speculative decoding change the model's output?&lt;/strong&gt;&lt;br&gt;
No. The technique is designed to be lossless. The target model verifies every proposed token with an acceptance rule that preserves its original output distribution, so the generated text is statistically identical to standard decoding from the target model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does speculative decoding help most at batch size one?&lt;/strong&gt;&lt;br&gt;
Single-stream decoding is memory-bandwidth bound: the processor reads the whole weight set to produce one token and spends most of its time waiting on memory. Verifying several proposed tokens in one pass reuses that single memory read, so the extra work is nearly free. At large batch sizes the target pass is already compute bound and the gain shrinks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does the draft model cost on a memory-constrained device?&lt;/strong&gt;&lt;br&gt;
The draft model must also stay resident in DRAM along with the target model and the key-value cache, and on a shared-memory SoC it competes for the same bandwidth. If it is too large, or its predictions are rejected often, it can erase the benefit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I try speculative decoding without changing my model?&lt;/strong&gt;&lt;br&gt;
Tools such as llama.cpp support it directly. You pass a small draft model with the -md or --model-draft option alongside the target model. No retraining or architecture change is needed, and the draft only needs a compatible vocabulary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Yaniv Leviathan, Matan Kalman, Yossi Matias, "Fast Inference from Transformers via Speculative Decoding", ICML 2023 (Oral). &lt;a href="https://arxiv.org/abs/2211.17192" rel="noopener noreferrer"&gt;arXiv:2211.17192&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;llama.cpp speculative decoding documentation. &lt;a href="https://github.com/ggml-org/llama.cpp/blob/master/docs/speculative.md" rel="noopener noreferrer"&gt;github.com/ggml-org/llama.cpp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;NVIDIA Jetson Orin Nano series datasheet (memory bandwidth figures). &lt;a href="https://connecttech.com/ftp/pdf/nvidia_jetson_orin_datasheet.pdf" rel="noopener noreferrer"&gt;Jetson Orin Nano datasheet (PDF)&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.techveda.live/2026/08/05/speculative-decoding-on-device-llm/" rel="noopener noreferrer"&gt;techveda.live&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>llm</category>
      <category>edgecomputing</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
