
Zephyr v4.5.0 was released on October 29, 2026. BayLibre contributed 376 authored commits this cycle, spanning a generic system-timer core and a reworked sleep and timeout API in the kernel, ARM64 memory management, the TF-M and Mbed TLS stack, a native LoRaWAN backend, and Renesas R-Car Gen5 bring-up.
That makes BayLibre the 10th largest contributing company to this release by authored commits, and the 2nd among companies that are not silicon vendors. Nicolas Pitre alone, with 201 commits, ranks 14th among all individual contributors. Beyond the numbers, BayLibre is also involved in the Zephyr Safety effort, where Alexandre Bailon works with the Safety Working Group toward the project’s functional-safety certification.
Kernel
Nicolas Pitre’s kernel work this cycle was largely consolidation: tick accounting that every timer driver had been re-deriving by hand, and a timeout-cancellation race that had been patched five separate times in five separate places, both moved into shared code.
System timer core
Every tickless system-timer driver in Zephyr carried its own copy of the same tick accounting: turning cycles into ticks, tracking what had already been announced, working out the next deadline. The copies were near-identical, subtly different where they were not, and a recurring source of timer bugs. Nicolas Pitre replaced the lot with a generic tickless system-timer core. A driver now describes its hardware — how its counter behaves, how wide it is, how fast it runs — and supplies a few primitives to read and arm it; the core does the rest, and because it is an included header rather than a library it compiles down against each driver’s own constants.
Moving the tree over took 23 driver conversions, each submitted separately so the people who own that hardware could review it. Every one of them deletes a private copy of the boilerplate, and some long-standing awkwardness goes with it: drivers whose comparator matches only on an exact counter value no longer need the minimum-delay floor they used to guess at, and SysTick derives its own from the clock rate instead of a Devicetree override. Out-of-tree drivers gain the most, as they no longer have to carry tick handling at all.
The work also turned up a configuration nobody had been running. CONFIG_SYSTEM_CLOCK_SLOPPY_IDLE, which lets uptime drift while the CPU is idle, was selected by no in-tree board and enabled by no test, so the drivers implementing it had never actually run. Several stop their time base outright — enough to freeze k_cycle_get_32() under a running thread, or hang k_busy_wait() — and some cannot restart it at all. It is now marked experimental and has CI coverage for the first time.
Timeout cancellation
The same consolidation happened a layer up. Cancelling a kernel timeout races with that timeout firing: there is a window where it has been pulled off the queue but its handler has not yet taken the lock that would make the cancellation safe. Five separate fixes for that one race had landed in five different parts of the kernel, each re-purposing the same magic sentinel value, and each quietly depending on that value surviving a k_free() of storage that may since have been reused — which left a use-after-free in place rather than removing one.
Nicolas moved the problem into the timeout subsystem itself. A single primitive, z_try_abort_timeout(), now tells a caller whether the timeout was cancelled, was never pending, or is firing right now on another CPU — in which case the caller drops its locks and retries. Timers, the scheduler, wait queues, timeslicing, poll and work all moved onto it, the old sentinel mechanism was deleted outright, and two further use-after-free windows closed along the way.
Timeout queue backends
Zephyr has always kept pending timeouts in a sorted delta list, which is compact and cheap to tick but grows expensive to insert into as timeouts pile up. That list is now one implementation behind an interface rather than the only option, with experimental min-heap, timer-wheel, bucketed and skip-list backends a build can select instead.
Sleep and timer API
Two k_timer behaviours were corrected by Nicolas: the start call now honours its documented minimum-delay contract, and the remaining-time call rounds up to the next millisecond.
Sleeping changed shape as well: k_sleep() and k_usleep() are now inlines over a new tick primitive, so the millisecond and microsecond conversions fold into the caller instead of being paid for on every call. On small builds that drops the 64-bit division helper entirely — 428 bytes of flash on the Cortex-M0 example cited — and it fixed k_usleep() failing to link in single-threaded configurations.
Scheduler, locking and printk
When a kernel dies, the one thing you want is the message saying why — and that was precisely when printk() could not be trusted. It takes a spinlock, so a fatal error raised while that lock was held, or by a CPU that would never release it, hung instead of printing; an assertion firing mid-message deadlocked on the same non-recursive lock; and on some architectures an early printk() faulted outright, because the atomics a spinlock is built from do not work until the MMU is on. Nicolas Pitre added printk_unlocked(), which takes no lock and skips the logging subsystem, and put the assert and fatal paths on it. Its output can interleave with a concurrent printk(), which beats losing the message altogether.
Nicolas also made net_buf reference counts atomic, closing an SMP race that could corrupt free lists under zbus, and simplified how the kernel probes interrupt state and hands spinlock ownership between threads.
Smaller fixes rounded out the cycle: a timeslice rearm bug that bit when the slicer had just fired, scheduler tests that now measure against the real cycles-per-tick instead of assumed values, and corrections across the logger, the static kernel heap and the lowercase min/max helpers.
Memory management and architecture
On ARM64, Carlo Caione made device MMIO identity-mapped by default: CPU_CORTEX_A now selects CONFIG_KERNEL_DIRECT_MAP when the MMU is enabled, and device registers are mapped at VA=PA instead of allocated from the SRAM range, with no per-board opt-in.
GIC register banks are now mapped by the ARM64 arch core from the arm,gic Devicetree node, so SoCs no longer repeat the same entries in their mmu_regions.c, and a SoC that needs only the GIC can drop the file. Carlo added the MmuRegionsCheck CI check, which flags newly added non-GIC entries there and redundant GIC ones.
Nicolas Pitre added LRU eviction to x86 demand paging, using the free PTE Global bit to mark tracked pages, and drops stale ARM64 cache lines over RAM before the region is used. On ARM64 the MMU page size became an ARM64_PAGE_SIZE Kconfig choice (4 KB, 16 KB or 64 KB), and page-table entries are dumped on a memory-fault exception. The pinned-section build machinery was removed.
Trusted firmware: TF-M, Mbed TLS and Corstone-1000
A new Arm FVP target covers the full Corstone-1000 secure-boot chain, brought up by Nicolas Pitre. Underneath it, Valerio Setti moved the crypto stack to Mbed TLS 4.1.1, TF-PSA-Crypto 1.1.1 and TF-M v2.3.0.
Nicolas added Corstone-1000-A320 FVP board support: TF-M in the secure enclave, TF-A BL2/BL31 with Zephyr as BL33, MCUboot verifying TF-A with ECDSA signatures, and a GPT flash image with a FIP partition, plus an SMP variant. The target builds with sysbuild and needs no network access.
The existing fvp_corstone1000 target was reworked to build its PSA CryptoCell driver from the new tf-psa-crypto-drivers module instead of cloning it at configure time; Nicolas added TF-A BL2 signing for MCUboot verification and re-enabled the board in twister.
Valerio Setti moved the crypto stack to Mbed TLS 4.1.1 and TF-PSA-Crypto 1.1.1 and TF-M to v2.3.0, and removed the mbedtls-3.6 module from the manifest. That module existed only for the TF-M 2.2 build and it became useless after the update.
Valerio moved the TF-M regression sample’s Kconfigs into the sample, which now passes the extra TF-M CMake parameters and runs its non-secure tests under a Zephyr application instead of the external RTX OS.
Two user-facing knobs moved: TFM_PUBLIC_KEY_FORMAT turns the image public-key storage choice into a Kconfig (full or hash), and the CMake interface library mbedTLS was renamed to mbedtls_iface with a backward-compatible alias and a migration-guide entry. Valerio also fixed a crash in single-threaded ARM builds, where libc access to TLS-backed variables had no TLS area defined.
LoRaWAN and LoRa
Carlo Caione introduced a preliminary.support for a Zephyr-native LoRaWAN 1.0.x Class A backend that talks directly to the LoRa radio driver, replacing the loramac-node module dependency. It uses PSA Crypto for AES-128, ships EU868 as its first region, and adds a public lorawan_request_link_check() API that queues a LinkCheckReq in the uplink or forces an empty uplink.
The LoRa drivers were hardened too: Carlo applied three documented SX1261/62 silicon errata, including an IQ-polarity fix after every packet-parameter write that could silently corrupt the inverted-IQ packets LoRaWAN downlinks use, and added hardware RX duty-cycle support to SX126x with a blocking variant.
The STM32WL low-power RFO duty-cycle setting for +15 dBm above 400 MHz was out of the documented range; Carlo corrected it, and minimum preamble length is now enforced for SF5 and SF6.
Renesas R-Car
Renesas’s R-Car Gen5 automotive family now has its first Zephyr support, from Julien Panis’s bring-up, spanning the X5H “Ironhide” board and the platform-management plumbing beneath it.
R-Car Gen5 platform
Julien Panis added R-Car Gen5 SoC series support — Cortex-R52 real-time cores — and the R-Car X5H Ironhide board, which targets ADAS, gateway and IVI products. Platform control runs through SCMI: power domains and resets use the SCMI protocols, Gen5 takes the SCMI clock driver rather than the CPG MSSR driver, and Julien supplied the Gen5 clock, power-domain and reset-domain IDs in the Devicetree bindings.
A Kconfig option to force polling-mode SCMI covers platforms without an interrupt-driven flow; Julien paired it with an MFIS mailbox driver for the interface between the R-Car’s application, real-time and control core domains. In the Devicetree, Gen5 declares I2C1–I2C8 and the Ironhide board enables I2C5. Julien also added an R-Car X5H pinctrl driver, using a node-based approach with optional SCMI-based pin configuration, and widened the R-Car pinctrl core’s pin index so SoCs with more than eight GPIO banks are addressable.
On Gen5 the gpio_rcar driver needs different register offsets and explicit pin-direction selection, so Julien adapted it. He also wrote a drivers: misc driver for the TI TDP2004 four-channel display redriver (DisplayPort 2.1 up to 20 Gbps, AC-coupled HDMI 2.1), wired to DisplayPort0 on Ironhide. Standalone fixes corrected the SCMI pinctrl client’s handling of zero configurations for function-only requests and a field in the SCMI_PINCTRL_CONFIG_ATTRIBUTES macro.
Adrien Ricciardi added generic clock access that abstracts Gen5’s SCMI clock-ID encoding and the pointer-based controllers of Gen3 and Gen4 behind one interface. He then moved the R-Car GPIO, I2C and serial drivers onto it, so each runs unchanged across generations 3, 4 and 5; the serial path was verified on Spider S4 and Ironhide X5H. He also added pinctrl support to the R-Car GPIO and I2C drivers, converted the I2C driver to device MMIO register access, and defined the remaining HSCIF default pins for the Ironhide CR52 cores.
RSCANFD CAN
A new R-Car RSCANFD CAN/CAN FD driver from Adrien Ricciardi has a global-controller binding and a separate per-channel binding; he declared the Gen5 controllers in the SoC Devicetree and added CAN nodes to the Ironhide X5H board with build-all coverage. Each RSCANFD instance exposes eight channels, all pin-defined on the board.
A cross-cutting API change documents -ENOTSUP for unsupported set_mode() modes on every CAN controller, since -EBUSY and -EIO cannot express “unsupported”. Adrien also raised the CAN shell’s argument limit so a full 64-byte CAN FD frame can be sent from the shell.
Buzzer subsystem
Carlo Caione added a buzzer subsystem, giving Zephyr a standard way to drive the small piezo and magnetic buzzers common on development boards.
The consumer-facing API Carlo added is buzzer_tone() and buzzer_beep(): one plays a frequency, the other a device’s natural tone from Devicetree, and volume and stop are part of the same interface. Two backends sit behind it — gpio-buzzer for active buzzers with their own oscillator and pwm-buzzer for passive piezos, where the PWM period sets pitch and the duty cycle encodes volume.
Eight boards were converted to the new compatibles, from the Seeed reTerminal family to the Arduino Nesso N1 and the NXP VMU RT1170, and Carlo enabled the on-board piezo on the BBC micro:bit v2. Both backends expose the same calls, so a board can move between an active and a passive part without driver changes.
Boards and input devices
A single board that carries Wi-Fi 6, BLE, 802.15.4 and sub-GHz LoRa exercises four radio stacks on one design, a combination Zephyr had not previously supported. Carlo Caione added the Arduino Nesso N1, an ESP32-C6 board co-designed by Arduino and M5Stack that combines Wi-Fi 6, BLE, 802.15.4 and sub-GHz LoRa. Follow-up commits enable its display, capacitive touch, buttons, SX1262 LoRa transceiver and buzzer.
Carlo Caione also added the Seeed Wio Tracker L1, an nRF52840 LoRa and GNSS tracker that flashes over UF2 rather than SWD, plus the X-NUCLEO-GNSS1A1 shield for the ST Teseo-LIV3F GNSS receiver. The tracker pairs its radio with a GNSS receiver, an OLED display and a five-way trackball.
A new virtio input driver forwards VIRTIO input events to the Zephyr input subsystem, with optional scaling to a referenced display’s resolution. Carlo added a virtio-tablet device to QEMU, and the LVGL pointer demos now run on QEMU with the host cursor kept visible.
Storage: ZMS
Mircea Caprioru gave Zephyr’s ZMS storage backend a wear-tracking API: zms_get_num_cycles() and zms_get_sector_num_cycles() report how many times a sector has been recycled, the input for estimating RRAM lifetime.
Two correctness fixes from Mircea matter. In 64-bit ID mode the cycle counter wrote over the allocation-entry bytes holding magic and version, so empty entries lost their metadata and sectors went unrecognized on remount. Separately, sector erase during garbage collection destroyed the cycle count before it was re-read, so the counter could never exceed 1. Counts are now read before erase, and the wipe path previously lost wear history entirely on RRAM/MRAM devices, where sector erase is a no-op.
Sensors and core driver APIs
Nicolas Belin added SENSOR_CHAN_VOLUME, a new public sensor channel for accumulated flow volume in liters, and a Hall-effect flow-meter driver behind a zephyr,flow-meter binding. The driver reports volume since boot and instantaneous flow rate, supports runtime calibration, and fires a one-shot volume threshold; a sample and a ztest suite run without real hardware, covering calibration changes, fractional volume conversion and the threshold.
Carlo Caione added syscon_update_bits() for an atomic read-modify-write under a single lock hold, with a per-device spinlock serializing concurrent consumers. Misaligned register offsets are now rejected instead of silently rounded down: with a 4-byte register width, offset 0x03 used to read register 0x00 and report no error.
Zephyr Safety
Alexandre Bailon has been working with Zephyr’s Safety Working Group, which is preparing the project for functional-safety certification, and this cycle he joined the Safety area’s collaborators.
At Open Source Summit Europe which has recently been held in Prague, Alexandre took part in the first dedicated Zephyr Safety Forum. The working group is aiming for certification next year, and is making progress on the full traceability chain and its tooling while keeping the process from placing excessive constraints on contributors and maintainers.
Miscellaneous
Kamil Jawański-Gawor word-aligned the nrf_etr debug driver’s shell output buffer so the logging fast-copy path can be used. Daniel Schultz fixed stray whitespace in the i.MX RT BOOT_SEMC_* Kconfig argument: the trailing space became part of the compatible string, so those options never matched the Devicetree and could not be enabled.
Carlo Caione also added a GPIO expander driver for the PI4IOE5V6408 and an ARM64 xlat-table exhaustion warning.
Summary
| Type | Count |
|---|---|
| Authored | 376 |
| Signed-off-by | 2 |
| Suggested-by | 6 |