Interactive Graph

Loading Graph...

BSP Topics

1. Linux Kernel Internals Importance: Understanding kernel internals is crucial for BSP and driver development as it helps in debugging, optimizing performance, and modifying the kernel to meet hardware-specific requirements. Topics: Kernel Architecture: Monolithic vs Microkernel, Kernel and User Space interactions. Process Management: Understanding task_struct, process states, scheduling algorithms. Interrupt Handling: SoftIRQs, tasklets, bottom halves, handling IRQs efficiently. Memory Management: Paging, kmalloc/vmalloc, slab allocator, ARM MMU and memory regions. Syscalls: How system calls work, writing custom syscalls. Kernel Synchronization: Spinlocks, mutexes, semaphores, barriers, RCU. Workqueues and Timers: Deferred execution, using timers for scheduling tasks. 2. Linux Device Drivers Importance: Device drivers are the bridge between hardware and the OS. Understanding drivers is crucial for embedded systems and BSP development. ...

February 4, 2025 · 2 min

Device Tree (DT) in Linux Kernel

Overview The Device Tree (DT) is a data structure used to describe the hardware components of a system in a way that is independent of the operating system and software. It is particularly relevant for systems based on the ARM architecture, where the hardware varies significantly across devices. Instead of hardcoding hardware details in the kernel, the device tree provides a flexible way to inform the kernel about the system’s hardware layout. This simplifies kernel code and enables easier reuse across multiple hardware platforms. ...

January 27, 2025 · 5 min

IOCTL in Kernel Device Drivers

ioctl Implementation in Kernel Device Drivers Overview ioctl (Input/Output Control) is a powerful system call in Linux used to perform device-specific operations that are not covered by standard system calls like read, write, or open. It allows user-space applications to interact with kernel-space drivers for device-specific configurations and data exchanges. How ioctl Works 1. User-Space Interaction: A user-space application invokes ioctl using the following prototype: int ioctl(int fd, unsigned long cmd, void *arg); fd: File descriptor for the device. cmd: Command defining the operation. arg: Pointer to the data or argument passed between user-space and kernel-space. 2. Driver-Side Handling: The ioctl system call is routed to the driver by the kernel. The driver implements a specific unlocked_ioctl or compat_ioctl callback in the file_operations structure. 3. Data Flow: Arguments passed via arg can be pointers to user-space data, requiring the driver to use helper functions like copy_from_user and copy_to_user for secure data transfer. Steps to Implement ioctl in a Kernel Driver 1. Define ioctl Commands: Use macros to define command numbers, typically with the _IO, _IOR, _IOW, and _IOWR macros provided in <linux/ioctl.h>. #define MY_IOCTL_BASE 'M' #define IOCTL_CMD_GET _IOR(MY_IOCTL_BASE, 1, int) #define IOCTL_CMD_SET _IOW(MY_IOCTL_BASE, 2, int) _IOR: Read data from the kernel. _IOW: Write data to the kernel. _IOWR: Read and write data. _IO: Command without data. 2. Implement ioctl Callback: Define the unlocked_ioctl function in the driver. Handle commands appropriately based on cmd. static long my_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int value; switch (cmd) { case IOCTL_CMD_GET: value = 1234; // Example value if (copy_to_user((int __user *)arg, &value, sizeof(value))) return -EFAULT; break; case IOCTL_CMD_SET: if (copy_from_user(&value, (int __user *)arg, sizeof(value))) return -EFAULT; pr_info("Value set by user: %d\n", value); break; default: return -ENOTTY; // Command not supported } return 0; } 3. Integrate into file_operations: Register the ioctl handler in the file_operations structure. static const struct file_operations my_fops = { .owner = THIS_MODULE, .open = my_open, .release = my_release, .unlocked_ioctl = my_ioctl, }; 4. Test the ioctl Implementation: Write a user-space application to interact with the driver. #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #define MY_IOCTL_BASE 'M' #define IOCTL_CMD_GET _IOR(MY_IOCTL_BASE, 1, int) #define IOCTL_CMD_SET _IOW(MY_IOCTL_BASE, 2, int) int main() { int fd, value = 42; fd = open("/dev/my_device", O_RDWR); if (fd < 0) { perror("Failed to open device"); return -1; } if (ioctl(fd, IOCTL_CMD_SET, &value) < 0) { perror("ioctl SET failed"); } if (ioctl(fd, IOCTL_CMD_GET, &value) < 0) { perror("ioctl GET failed"); } else { printf("Value from device: %d\n", value); } close(fd); return 0; } Best Practices for ioctl Use Explicit Command Definitions: Follow a consistent naming convention for command macros. Secure User-Kernel Data Transfer: Always validate pointers and sizes. Use copy_from_user and copy_to_user for safe data exchange. Error Handling: Return appropriate error codes for unsupported commands or invalid inputs. Limit ioctl Usage: Avoid using ioctl for operations that can be implemented using read or write. Magic Number: Ensure it’s unique (check Documentation/ioctl/ioctl-number.txt in kernel sources). Atomicity: Use locks if hardware operations are not atomic. Cross-Platform: Handle 32/64-bit compatibility with compat_ioctl if needed. Real-World Example: Custom ARM Board For a custom ARM board, you might need an ioctl to configure hardware parameters like GPIO modes or clock frequencies. ...

January 24, 2025 · 4 min

Problem - fw_printenv does not print bootloader env variables

Problem In bootloader the environment variables are accessible. The values could be accessed and modified perfectly from bootloader cli (hush shell). When booting to the linux kernel and accessing from bash shell (userspace) through fw_printenv the environment variables are not accessible. Getting following logs: Warning: Bad CRC, using default environment Setup: Using MMC storage The /etc/fw_env.config file has following entry and the offset and size are same from uboot’s .config file /dev/mmcblk0p2 0x3f8000 0x8000 Uboot Environment in RK3588 Uboot Config config ENV_OFFSET hex "Environment offset" depends on !ENV_IS_IN_UBI depends on !ENV_IS_NOWHERE || ENVF default 0x0 if ENVF default 0x3f8000 help Offset from the start of the device (or partition) config ENV_SIZE hex "Environment size" default 0x8000 help Size of the environment storage area Parameters CONFIG_ENV_SIZE=0x8000 --> 32K CONFIG_ENV_OFFSET=0x3f8000 --> 4096-32=4064 4096K=4M u-boot/tools/env/fw_env.c Either crc0_ok = (crc0 == *environment.crc); is invalid ...

December 4, 2024 · 4 min

Kernel Log Level

Number Macro Log Level Description Equivalent 0 pr_emerg Emergency System is unusable. KERN_EMERG 1 pr_alert Alert Action must be taken immediately. KERN_ALERT 2 pr_crit Critical Critical conditions. KERN_CRIT 3 pr_err Error Error conditions. KERN_ERR 4 pr_warn Warning Warning conditions. KERN_WARNING 5 pr_notice Notice Normal but significant condition. KERN_NOTICE 6 pr_info Informational Informational messages. KERN_INFO 7 pr_debug pr_devel Debug Debugging messages. pr_debug() and pr_devel() if DEBUG is defined KERN_DEBUG The number corresponds to the log level used by the Linux kernel, with lower numbers indicating higher severity. For example, if the log level is set to 4 (Warning), only messages from pr_emerg to pr_warn will appear in the system logs. Default log level is generally set to 6. You can check the current console_loglevel with: cat /proc/sys/kernel/printk 4 4 1 7 echo 8 > /proc/sys/kernel/printk dmesg -n 5 Reference https://www.kernel.org/doc/html/next/core-api/printk-basics.html

November 20, 2024 · 1 min

Making File System

Overview Get the final files into a directory eg. target and treat it as root(/) directory of target board/system. Generate users eg. root, admin, ssh, etc Generate device lists Clean few files Generate ext image using mkfs Taking reference from buildroot common.mk and ext2.mk scripts/makedevs -d output/build/buildroot-fs/full_devices_table.txt output/build/buildroot-fs/ext2/target mkfs.ext4 -d output/build/buildroot-fs/ext2/target -r 1 -N 0 -m 5 -L rootfs -O ^64bit output/images/rootfs.ext2 2G # Fakeroot execution complete /opt/rk3588_nvrx/host/sbin/resize2fs -M output/images/rootfs.ext2 /opt/rk3588_nvrx/host/sbin/e2fsck -fy /output/images/rootfs.ext2 /opt/rk3588_nvrx/host/sbin/resize2fs -M /output/images/rootfs.ext2 Fakeroot Script #!/bin/sh set -ex chown -h -R 0:0 $(TARGET) $(HOST_DIR)/bin/makedevs -d full_devices_table.txt $(TARGET) $(HOST_DIR)/sbin/mkfs.ext4 -d $(TARGET) -r 1 -N 0 -m 5 -L "rootfs" -O ^64bit rootfs.ext2 "2G" Post EXT4 $(HOST_DIR)/sbin/resize2fs -M rootfs.ext2 $(HOST_DIR)/sbin/e2fsck -fy rootfs.ext2 $(HOST_DIR)/sbin/tune2fs -m 5 rootfs.ext2 $(HOST_DIR)/sbin/resize2fs -M rootfs.ext2 Testing on Host sudo mount -o loop path/to/rootfs.ext4 /tmp/fs_path Makedevs Creates a batch of special files as specified in a device table. ...

November 11, 2024 · 3 min

I2C

Basics of I2C Overview Synchronous, multi-master, multi-slave serial bus. Half-duplex communication (bidirectional SDA line). Uses 2 wires: SCL (clock), SDA (data). Speeds: Standard (100 kHz), Fast (400 kHz), High-Speed (3.4 MHz). Physical Layer Open-drain outputs – requires pull-up resistors. 7-bit or 10-bit addressing (supports up to 128/1024 devices). Data Frame Structure Start condition: SDA ↓ while SCL is high. Address frame: 7/10-bit address + R/W bit. ACK/NACK: Slave pulls SDA low to acknowledge. Data frames (8-bit chunks, MSB-first). Stop condition: SDA ↑ while SCL is high. Start | Address | Read/Write | ACK/NACK | Data | Stop Key Features Clock stretching: Slaves can hold SCL low to pause communication. Multi-master arbitration: Masters detect collisions via SDA monitoring. Speeds: Standard (100 kbps), Fast (400 kbps), High-Speed (3.4 Mbps). Use Cases Sensors (temperature, accelerometers). EEPROMs, RTC (Real-Time Clock) modules. Device Tree TODO Writing client device drivers TODO I2C-Tools Package in Userspace Useful for debugging, testing, some simple prototyping Accesses the I²C bus via /dev/i2c-0, /dev/i2c-1… Assume devices have registers, SMBus-like i2cdetect scan an I2C bus for devices No guarantee it works (I²C is not discoverable by the spec) [rishav] ➜ ~ i2cdetect -l i2c-0 i2c i915 gmbus dpc I2C adapter i2c-1 i2c i915 gmbus dpb I2C adapter i2c-2 i2c i915 gmbus dpd I2C adapter i2c-3 i2c AUX A/DDI A/PHY A I2C adapter i2c-4 unknown Synopsys DesignWare I2C adapter N/A i2c-5 unknown Synopsys DesignWare I2C adapter N/A i2c-6 unknown SMBus I801 adapter at f040 N/A [rishav] ➜ ~ i2cdetect -y 2 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- 28 -- -- -- -- -- -- -- 30: -- -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- -- No response 28 Response from address 28 UU Address in use (by driver) i2cget, i2cset i2cget: read a register value i2cset: set a register value Can use various types of SMBus and I2C transactions Limited to 8-bit register address # i2cget -y 2 0x28 0x1b 0x21 # i2cset -y 2 0x28 0x55 # i2cdump dump value of all registers i2ctransfer i2ctransfer: the “swiss army knife of Linux I2C”, in userspace Example: reimplement the i2cget -y 2 0x28 0x1b command: # i2ctransfer -y 2 w1@0x28 0x1b r1@0x28 0x21 # w1@0x28 Write transaction, 1 byte, client address 0x28 0x1b Data to send in the write transaction r1@0x28 Read transaction, 1 byte, client address 0x28 Troubleshooting Return code from i2c_*() functions — Never ignore errors! Kernel logs i2c-tools Oscilloscope or logic analyzer No ACK from client - systematic Problem: a client never responds to transactions ...

November 8, 2024 · 4 min

Example Image Tree Source File (.its)

Example Image Tree Source (.its) file /dts-v1/; / { description = "U-Boot FIT source file for arm"; images { uboot { data = /incbin/("uboot.img.enc"); type = "standalone"; arch = "arm64"; compression = "none"; load = <0xffffff00>; hash { algo = "sha256"; }; }; }; configurations { default = "conf"; conf { rollback-index = <0x00>; uboot = "uboot"; board-type = "MU_BOARD"; signature { algo = "sha256,rsa2048"; padding = "pss"; key-name-hint = "dev"; sign-images = "uboot"; }; }; }; }; References https://devicetree-specification.readthedocs.io/en/stable/index.html

November 8, 2024 · 1 min

Flattened Devicetree (DTB) Format

Device Tree Standard Properties compatible The compatible property value consists of one or more strings that define the specific programming model for the device. This list of strings should be used by a client program for device driver selection. The property value consists of a concatenated list of null terminated strings, from most specific to most general. They allow a device to express its compatibility with a family of similar devices, potentially allowing a single device driver to match against several devices. ...

November 8, 2024 · 1 min

mkimage

Overview U-Boot expects all bootable files (kernel, device tree blobs, initramfs, scripts, etc.) to have a specific image format called U-Boot Image Format (uImage format). mkimage generates this format. Signing images Generate signed image build/uboot/tools/mkimage -k config/keys/secureboot -f boot.its boot.img Dump information dumpimage -l boot-temp.img Resign the image build/uboot/tools/mkimage -F -k config/keys/secureboot boot.img Directory Structure Expected by -k /path/to/keys/ ├── dev.key <-- Private key (used by mkimage) ├── dev.crt <-- X.509 certificate (optional) ├── dev.pub <-- Public key (for embedding in U-Boot, or image) The filename prefix (dev) maps to the key-name in the .its file. ...

November 5, 2024 · 1 min