r/embeddedlinux 45m ago

I’m building a semantic engine for Linux Device Trees

Upvotes

One thing I've found increasingly frustrating when working with Linux Device Trees is that the information you need is rarely in one place.

A node in a .dts file might depend on information from:

  • DTS/DTSI includes
  • YAML bindings
  • dt-schema
  • kernel drivers
  • SoC documentation
  • board-specific files
  • phandles and references
  • Device Tree overlays

The information is there, but understanding how all these pieces relate often means jumping between different files, repositories and tools.

There are already tools that handle some of these problems individually. What I couldn't find was something that connects the different layers of Device Tree knowledge together.

So I've been building DTstudio, a semantic engine for Linux Device Trees.

Instead of treating a Device Tree simply as a text file or a hierarchy, I'm trying to build a semantic model of what the nodes, properties, bindings and references actually mean.

For example, the goal is to go from:

node → compatible → binding → property definition → constraints → referenced nodes → related hardware

and keep that context available while working on the tree.

The editor is essentially the interface for exploring that knowledge.

Here's a short GIF of the current implementation:

It's still in beta and there is a lot more I want to figure out.

For people working with Linux Device Trees:

What information do you usually have to look up manually when working on a DTS?

I'm particularly interested in the things that technically exist somewhere in the kernel, bindings or documentation, but are difficult to discover or connect together.

Free download on: dt-studio.dev


r/embeddedlinux 13h ago

Deterministic Memory Scrubbing and Signal-Safe Zeroization in Low-Level Embedded Runtimes

0 Upvotes

When handling high-integrity volatile states, standard userspace teardown or garbage collection can leave residual data fragments in RAM if a process faults unexpectedly.
Here is a minimal, low-level C pattern demonstrating how to pin sensitive buffers using ⁠mlock()⁠, prevent compiler optimizations during clearing via ⁠volatile⁠ pointers, and intercept abrupt termination signals (⁠SIGSEGV⁠, ⁠SIGINT⁠) to enforce deterministic memory scrubbing before exit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/mman.h>

#define BUFFER_SIZE 4096

static volatile unsigned char *secure_buffer = NULL;

void secure_zeroize(volatile unsigned char *v, size_t n) {
volatile unsigned char *p = v;
while (n--) {
*p++ = 0;
}
}

void emergency_signal_handler(int sig) {
if (secure_buffer != NULL) {
secure_zeroize(secure_buffer, BUFFER_SIZE);
munlock((void *)secure_buffer, BUFFER_SIZE);
}
_exit(128 + sig);
}

int main(void) {
secure_buffer = (volatile unsigned char *)malloc(BUFFER_SIZE);
if (!secure_buffer) return 1;

if (mlock((void *)secure_buffer, BUFFER_SIZE) != 0) {
perror("mlock failed");
free((void *)secure_buffer);
return 1;
}

signal(SIGSEGV, emergency_signal_handler);
signal(SIGINT, emergency_signal_handler);

memset((void *)secure_buffer, 0xAA, BUFFER_SIZE);

// Normal cleanup path
secure_zeroize(secure_buffer, BUFFER_SIZE);
munlock((void *)secure_buffer, BUFFER_SIZE);
free((void *)secure_buffer);

return 0;
}
Key considerations in this pattern:
⁠mlock⁠: Prevents the buffer from being swapped out to persistent storage or unencrypted disk partitions.
⁠volatile⁠ casting: Ensures the compiler optimization passes do not strip away the zeroization loop as "dead writes".
Signal safety: Bypasses heavy userspace runtimes during fault handling to ensure immediate state destruction.
How do you typically approach hardware-adjacent or kernel-enforced data wiping in your architectures when dealing with abrupt power or state anomalies