Bootlin Linux Kernel Slides
Bootlin Linux Kernel Slides
Corrections, suggestions, contributions and translations are welcome! embedded Linux and kernel engineering
Send them to [email protected]
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 1/470
Rights to copy
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 2/470
Hyperlinks in the document
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 3/470
Company at a glance
https://elixir.bootlin.com
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 5/470
Generic course information
Generic course
information
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 6/470
Supported hardware
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 7/470
Shopping list: hardware for this course
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 8/470
Participate!
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 9/470
Practical lab guidelines
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 10/470
Advise: write down your commands!
During practical labs, write down all your commands in a text file.
▶ You can save a lot of time re-using commands Lab commands
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 11/470
Cooperate!
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 12/470
Practical lab - Training Setup
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 13/470
Linux Kernel Introduction
Linux Kernel
Introduction
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 14/470
Linux Kernel Introduction
Linux features
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 15/470
History
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 16/470
Linux kernel key features
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 17/470
Linux kernel in the system
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 18/470
Linux kernel main roles
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 19/470
System calls
▶ Linux makes system and kernel information available in user space through
pseudo filesystems, sometimes also called virtual filesystems
▶ Pseudo filesystems allow applications to see directories and files that do not exist
on any real storage: they are created and updated on the fly by the kernel
▶ The two most important pseudo filesystems are
▶ proc, usually mounted on /proc:
Operating system related information (processes, memory management
parameters...)
▶ sysfs, usually mounted on /sys:
Representation of the system as a tree of devices connected by buses. Information
gathered by the kernel frameworks managing these devices.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 21/470
Inside the Linux kernel
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 22/470
Linux license
▶ The whole Linux sources are Free Software released under the GNU General
Public License version 2 (GPL v2).
▶ For the Linux kernel, this basically implies that:
▶ When you receive or buy a device with Linux on it, you should receive the Linux
sources, with the right to study, modify and redistribute them.
▶ When you produce Linux based devices, be prepared to release the sources to the
recipient, with the same rights, with no restriction.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 23/470
Supported hardware architectures
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 24/470
Embedded Linux Kernel Usage
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 25/470
Embedded Linux Kernel Usage
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 26/470
Location of kernel sources
▶ The official (mainline) versions of the Linux kernel, as released by Linus Torvalds,
are available at https://kernel.org
▶ These versions follow the development model of the kernel
▶ However, they may not contain the latest development from a specific area yet.
Some features in development might not be ready for mainline inclusion yet.
▶ Many chip vendors supply their own kernel sources
▶ Focusing on hardware support first
▶ Can have a very important delta with mainline Linux
▶ Useful only when mainline hasn’t caught up yet. Many vendors invest in the
mainline kernel at the same time.
▶ Many kernel sub-communities maintain their own kernel, with usually newer but
fewer stable features
▶ Architecture communities (ARM, MIPS, PowerPC, etc.), device drivers communities
(I2C, SPI, USB, PCI, network, etc.), other communities (real-time, etc.)
▶ No official releases, only meant for sharing work and contributing to the mainline
version.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 27/470
Getting Linux sources
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 28/470
Linux kernel size (1)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 29/470
Linux kernel size (2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 30/470
Practical lab - Downloading kernel source code
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 31/470
Kernel Source Code
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 32/470
Kernel Source Code
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 33/470
Programming language
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 34/470
No C library
▶ The kernel has to be standalone and can’t use user space code.
▶ Architectural reason: user space is implemented on top of kernel services, not the
opposite.
▶ Technical reason: the kernel is on its own during the boot up phase, before it has
accessed a root filesystem.
▶ Hence, kernel code has to supply its own library implementations (string utilities,
cryptography, uncompression...)
▶ So, you can’t use standard C library functions in kernel code (printf(),
memset(), malloc(),...).
▶ Fortunately, the kernel provides similar C functions for your convenience, like
printk(), memset(), kmalloc(), ...
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 35/470
Portability
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 36/470
No stable Linux internal API
✘ DRM
▶ Of course, the kernel to user space API does not change in Linux kernel 4.0
Image credits (Wikipedia):
(system calls, /proc, /sys), as it would break existing https://bit.ly/2U2rdGB
programs.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 37/470
Kernel memory constraints
▶ No memory protection
▶ The kernel doesn’t try to recover from attemps to access illegal memory locations.
It just dumps oops messages on the system console.
▶ Fixed size stack (8 or 4 KB). Unlike in user space, no mechanism was
implemented to make it grow. Don’t use recursion!
▶ Swapping is not implemented for kernel memory either
(Exception: tmpfs filesystem pages)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 38/470
Linux kernel licensing constraints
▶ The Linux kernel is licensed under the GNU General Public License version 2
▶ This license gives you the right to use, study, modify and share the software freely
▶ However, when the software is redistributed, either modified or unmodified, the
GPL requires that you redistribute the software under the same license, with the
source code
▶ If modifications are made to the Linux kernel (for example to adapt it to your
hardware), it is a derivative work of the kernel, and therefore must be released under
GPLv2
▶ The validity of the GPL on this point has already been verified in courts
▶ However, you’re only required to do so
▶ At the time the device starts to be distributed
▶ To your customers, not to the entire world
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 39/470
Proprietary code and the kernel
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 40/470
Advantages of GPL drivers
▶ You don’t have to write your driver from scratch. You can reuse code from similar
free software drivers.
▶ You could get free community contributions, support, code review and testing,
though this generally only happens with code submitted for the mainline kernel.
▶ Your drivers can be freely and easily shipped by others (for example by Linux
distributions or embedded Linux build systems).
▶ Pre-compiled drivers work with only one kernel version and one specific
configuration, making life difficult for users who want to change the kernel version.
▶ Legal certainty, you are sure that a GPL driver is fine from a legal point of view.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 41/470
Advantages of in-tree kernel drivers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 42/470
User space device drivers 1/3
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 43/470
User space device drivers 2/3
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 44/470
User space device drivers 3/3
▶ Advantages
▶ No need for kernel coding skills. Easier to reuse code between devices.
▶ Drivers can be written in any language, even Perl!
▶ Drivers can be kept proprietary.
▶ Driver code can be killed and debugged. Cannot crash the kernel.
▶ Can be swapped out (kernel code cannot be).
▶ Can use floating-point computation.
▶ Less in-kernel complexity.
▶ Potentially higher performance, especially for memory-mapped devices, thanks to the
avoidance of system calls.
▶ Drawbacks
▶ Missing hardware abstraction provided by the kernel, need to adapt applications
when replacing one device by another.
▶ Less straightforward to handle interrupts.
▶ Increased interrupt latency vs. kernel code.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 45/470
Kernel Source Code
Linux sources
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 46/470
Linux sources structure 1/5
▶ arch/<ARCH>
▶ Architecture specific code
▶ arch/<ARCH>/mach-<machine>, SoC family specific code
▶ arch/<ARCH>/include/asm, architecture-specific headers
▶ arch/<ARCH>/boot/dts, Device Tree source files, for some architectures
▶ block/
▶ Block layer core
▶ certs/
▶ Management of certificates for key signing
▶ COPYING
▶ Linux copying conditions (GNU GPL)
▶ CREDITS
▶ Linux main contributors
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 47/470
Linux sources structure 2/5
▶ crypto/
▶ Cryptographic libraries
▶ Documentation/
▶ Kernel documentation sources
Generated documentation available on https://kernel.org/doc/
(includes functions prototypes and comments extracted from source code).
▶ drivers/
▶ All device drivers except sound ones (usb, pci...)
▶ fs/
▶ Filesystems (fs/ext4/, etc.)
▶ include/
▶ Kernel headers
▶ include/linux/
▶ Linux kernel core headers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 48/470
Linux sources structure 3/5
▶ include/uapi/
▶ User space API headers
▶ init/
▶ Linux initialization (including init/main.c)
▶ ipc/
▶ Code used for Inter Process Communication
▶ Kbuild
▶ Part of the kernel build system
▶ Kconfig
▶ Top level description file for configuration parameters
▶ kernel/
▶ Linux kernel core (very small!)
▶ lib/
▶ Misc library routines (zlib, crc32...)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 49/470
Linux sources structure 4/5
▶ MAINTAINERS
▶ Maintainers of each kernel part. Very useful!
▶ Makefile
▶ Top Linux Makefile (sets version information)
▶ mm/
▶ Memory management code (small too!)
▶ net/
▶ Network support code (not drivers)
▶ README
▶ Description of kernel documentation
▶ samples/
▶ Sample code (markers, kprobes, kobjects, bpf...)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 50/470
Linux sources structure 5/5
▶ scripts/
▶ Executables for kernel building and debugging
▶ security/
▶ Security model implementations (SELinux...)
▶ sound/
▶ Sound support code and drivers
▶ tools/
▶ Code for various user space tools (mostly C, example: perf)
▶ usr/
▶ Code to generate an initramfs cpio archive
▶ virt/
▶ Virtualization support (KVM)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 51/470
Kernel Source Code
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 52/470
Cscope
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 53/470
Cscope screenshot
▶ https://github.com/bootlin/elixir
▶ Generic source indexing tool and code browser for C and C++. Inspired by the
LXR project (Linux Cross Reference).
▶ Web server based, very easy and fast to use
▶ Very easy to find the declaration, implementation or usage of symbols
▶ Supports huge code projects such as the Linux kernel with a git repository. Scales
much better than LXR by only indexing new git objects found in each new release.
▶ Takes a little time and patience to setup (configuration, indexing, web server
configuration)
▶ You don’t need to set up Elixir by yourself. Use our
https://elixir.bootlin.com server!
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 55/470
https://elixir.bootlin.com
Project
selection Current
(U-Boot, directory
Linux,
BusyBox...)
Identifier
search
Source
browsing
All versions
available
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 56/470
Text editors and IDEs for kernel development
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 57/470
Practical lab - Kernel Source Code - Exploring
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 58/470
Kernel Source Code
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 59/470
Kernel Source Code
Kernel configuration
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 60/470
Kernel configuration
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 61/470
Kernel configuration and build system
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 62/470
Specifying the target architecture
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 63/470
Choose a compiler
The compiler invoked by the kernel Makefile is $(CROSS_COMPILE)gcc
▶ Specifying the compiler is already needed at configuration time, as some kernel
configuration options depend on the capabilities of the compiler.
▶ When compiling natively
▶ Leave CROSS_COMPILE undefined and the kernel will be natively compiled for the host
architecture using gcc.
▶ When using a cross-compiler
▶ To make the difference with a native compiler, cross-compiler executables are
prefixed by the name of the target system, architecture and sometimes library.
Examples:
mips-linux-gcc: the prefix is mips-linux-
arm-linux-gnueabi-gcc: the prefix is arm-linux-gnueabi-
▶ So, you can specify your cross-compiler as follows:
export CROSS_COMPILE=arm-linux-gnueabi-
CROSS_COMPILE is actually the prefix of the cross compiling tools
(gcc, as, ld, objcopy, strip...).
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 64/470
Specifying ARCH and CROSS_COMPILE
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 65/470
Kernel configuration details
▶ The configuration is stored in the .config file at the root of kernel sources
▶ Simple text file, CONFIG_PARAM=value (included by the kernel Makefile)
▶ As options have dependencies, typically never edited by hand, but through
graphical or text interfaces:
▶ make xconfig, make gconfig (graphical)
▶ make menuconfig, make nconfig (text)
▶ You can switch from one to another, they all load/save the same .config file, and
show the same set of options
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 66/470
Initial configuration
Difficult to find which kernel configuration will work with your hardware and root
filesystem. Start with one that works!
▶ Desktop or server case:
▶ Advisable to start with the configuration of your running kernel, usually available in
/boot:
cp /boot/config-`uname -r` .config
▶ Embedded platform case (at least on ARM 32 bit):
▶ Default configuration files are available, usually for each CPU family.
▶ They are stored in arch/<arch>/configs/, and are just minimal .config files (only
settings different from default ones).
▶ Run make help to find if one is available for your platform
▶ To load a default configuration file, just run
make cpu_defconfig
▶ This will overwrite your existing .config file!
Now, you can make configuration changes (make menuconfig...).
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 67/470
Create your own default configuration
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 68/470
Kernel or module?
▶ The kernel image is a single file, resulting from the linking of all object files that
correspond to features enabled in the configuration
▶ This is the file that gets loaded in memory by the bootloader
▶ All included features are therefore available as soon as the kernel starts, at a time
where no filesystem exists
▶ Some features (device drivers, filesystems, etc.) can however be compiled as
modules
▶ These are plugins that can be loaded/unloaded dynamically to add/remove features
to the kernel
▶ Each module is stored as a separate file in the filesystem, and therefore access
to a filesystem is mandatory to use modules
▶ This is not possible in the early boot procedure of the kernel, because no filesystem
is available
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 69/470
Kernel option types
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 70/470
Kernel option dependencies
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 71/470
make xconfig
make xconfig
▶ The most common graphical interface to configure the kernel.
▶ File browser: easier to load configuration files
▶ Search interface to look for parameters
▶ Required Debian / Ubuntu packages: qt5-default
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 72/470
make xconfig screenshot
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 73/470
make xconfig search interface
Looks for a keyword in the parameter name (shortcut: [Ctrl] + [f]).
Allows to set values to found parameters.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 74/470
Kernel configuration options
Driver options
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 75/470
Corresponding .config file excerpt
Options are grouped by sections and are prefixed with CONFIG_.
#
# CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
CONFIG_UDF_FS=y
CONFIG_UDF_NLS=y
#
# DOS/FAT/NT Filesystems
#
# CONFIG_MSDOS_FS is not set
# CONFIG_VFAT_FS is not set
CONFIG_NTFS_FS=m
# CONFIG_NTFS_DEBUG is not set
CONFIG_NTFS_RW=y
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 76/470
make gconfig
make gconfig
▶ GTK based graphical configuration
interface. Functionality similar to that
of make xconfig.
▶ Just lacking a search functionality.
▶ Required Debian packages:
libglade2-dev
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 77/470
make menuconfig
make menuconfig
▶ Useful when no graphics are available.
Very efficient interface.
▶ Same interface found in other tools:
BusyBox, Buildroot...
▶ Convenient number shortcuts to jump
directly to search results.
▶ Required Debian packages:
libncurses-dev
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 78/470
make nconfig
make nconfig
▶ A newer, similar text interface
▶ More user friendly (for example, easier
to access help information).
▶ However, lacking the shortcuts that
menuconfig offers in search results.
Therefore, much less convenient than
menuconfig.
▶ Required Debian packages:
libncurses-dev
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 79/470
make oldconfig
make oldconfig
▶ Needed very often!
▶ Useful to upgrade a .config file from an earlier kernel release
▶ Asks for values for new parameters.
▶ ... unlike make menuconfig and make xconfig which silently set default values
for new parameters.
If you edit a .config file by hand, it’s useful to run make oldconfig afterwards, to set
values to new parameters that could have appeared because of dependency changes.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 80/470
Undoing configuration changes
A frequent problem:
▶ After changing several kernel configuration settings, your kernel no longer works.
▶ If you don’t remember all the changes you made, you can get back to your
previous configuration:
$ cp .config.old .config
▶ All the configuration interfaces of the kernel (xconfig, menuconfig,
oldconfig...) keep this .config.old backup copy.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 81/470
Kernel Source Code
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 82/470
Kernel compilation
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 83/470
Kernel compilation results
▶ vmlinux, the raw uncompressed kernel image, in the ELF format, useful for
debugging purposes, but cannot be booted
▶ arch/<arch>/boot/*Image, the final compressed kernel image that can be
booted
▶ bzImage for x86, zImage for ARM, Image.gz for RISC-V, vmlinux.bin.gz for ARC,
etc.
▶ arch/<arch>/boot/Image, uncompressed kernel image that can be booted too
▶ arch/<arch>/boot/dts/*.dtb, compiled Device Tree files (on some
architectures)
▶ All kernel modules, spread over the kernel source tree, as .ko (Kernel Object) files.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 84/470
Kernel installation: native case
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 85/470
Kernel installation: embedded case
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 86/470
Module installation: native case
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 87/470
Automatic module loading with module aliases
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 88/470
Module installation: embedded case
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 89/470
Kernel cleanup targets
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 90/470
Kernel building overview
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 91/470
Kernel Source Code
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 92/470
Device Tree (1)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 93/470
Device Tree (2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 94/470
Customize your board device tree!
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 95/470
Booting with U-Boot
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 96/470
Kernel command line
▶ In addition to the compile time configuration, the kernel behavior can be adjusted
with no recompilation using the kernel command line
▶ The kernel command line is a string that defines various arguments to the kernel
▶ It is very important for system configuration
▶ root= for the root filesystem (covered later)
▶ console= for the destination of kernel messages
▶ Example: console=ttyS0 root=/dev/mmcblk0p2 rootwait
▶ Many more exist. The most important ones are documented in
admin-guide/kernel-parameters in kernel documentation.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 97/470
DT fixups and passing the kernel command line
On platforms with the Device Tree, U-Boot actually fixes the DT before passing it to the Linux kernel:
▶ U-Boot checks the device tree loaded in RAM or directly provides
its own. See the ”Understanding U-Boot Falcon
Mode” presentation from Michael
▶ U-Boot checks the specifics of the hardware (amount and location Opdenacker, for details about how U-Boot
boots Linux.
of RAM, MAC address, present devices...), possibly loads
corresponding Device Tree overlays, and modifies (fixes-up) the
Device Tree accordingly.
▶ U-Boot stores the Linux kernel command line string (bootargs) in
the chosen section in the Device Tree.
▶ Then the kernel can:
▶ Append this string to the default command line
(CONFIG_CMDLINE) if CONFIG_CMDLINE_EXTEND is set
Slides: https:
▶ Use only this string if //bootlin.com/pub/conferences/2021/lee/
Video: https:
CONFIG_CMDLINE_FROM_BOOTLOADER is set //www.youtube.com/watch?v=LFe3x2QMhSo
▶ Use only CONFIG_CMDLINE if CONFIG_CMDLINE_FORCE is
set.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 98/470
Practical lab - Kernel compiling and booting
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 99/470
Kernel Source Code
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 100/470
Advantages of modules
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 101/470
Module dependencies
▶ Some kernel modules can depend on other modules, which need to be loaded first.
▶ Example: the ubifs module depends on the ubi and mtd modules.
▶ Dependencies are described both in
/lib/modules/<kernel-version>/modules.dep and in
/lib/modules/<kernel-version>/modules.dep.bin (binary hashed format)
These files are generated when you run make modules_install.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 102/470
Kernel log
When a new module is loaded, related information is available in the kernel log.
▶ The kernel keeps its messages in a circular buffer (so that it doesn’t consume
more memory with many messages)
▶ Kernel log messages are available through the dmesg command (diagnostic
message)
▶ Kernel log messages are also displayed in the system console (console messages
can be filtered by level using the loglevel kernel command line parameter, or
completely disabled with the quiet parameter). Example:
console=ttyS0 root=/dev/mmcblk0p2 loglevel=5
▶ Note that you can write to the kernel log from user space too. That’s useful when
your device’s serial console is being monitored for critical messages:
echo "<n>Debug info" > /dev/kmsg
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 103/470
Module utilities (1)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 104/470
Understanding module loading issues
▶ When loading a module fails, insmod often doesn’t give you enough details!
▶ Details are often available in the kernel log.
▶ Example:
$ sudo insmod ./intr_monitor.ko
insmod: error inserting './intr_monitor.ko': -1 Device or resource busy
$ dmesg
[17549774.552000] Failed to register handler for irq channel 2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 105/470
Module utilities (2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 106/470
Module utilities (3)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 107/470
Passing parameters to modules
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 108/470
Check module parameter values
How to find/edit the current values for the parameters of a loaded module?
▶ Check /sys/module/<name>/parameters.
▶ There is one file per parameter, containing the parameter value.
▶ Also possible to change parameter values if these files have write permissions
(depends on the module code).
▶ Example:
echo 0 > /sys/module/usb_storage/parameters/delay_use
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 109/470
Useful reading
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 110/470
Developing kernel modules
Developing kernel
modules
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 111/470
Hello module 1/2
// SPDX-License-Identifier: GPL-2.0
/* hello.c */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Greeting module");
MODULE_AUTHOR("William Shakespeare");
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 112/470
Hello module 2/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 113/470
Hello module explanations
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 114/470
Symbols exported to modules 1/2
▶ From a kernel module, only a limited number of kernel functions can be called
▶ Functions and variables have to be explicitly exported by the kernel to be visible
to a kernel module
▶ Two macros are used in the kernel to export functions and variables:
▶ EXPORT_SYMBOL(symbolname), which exports a function or variable to all modules
▶ EXPORT_SYMBOL_GPL(symbolname), which exports a function or variable only to GPL
modules
▶ Linux 5.3: contains the same number of symbols with EXPORT_SYMBOL() and
symbols with EXPORT_SYMBOL_GPL()
▶ A normal driver should not need any non-exported function.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 115/470
Symbols exported to modules 2/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 116/470
Module license
▶ Several usages
▶ Used to restrict the kernel functions that the module can use if it isn’t a GPL
licensed module
▶ Difference between EXPORT_SYMBOL() and EXPORT_SYMBOL_GPL()
▶ Used by kernel developers to identify issues coming from proprietary drivers, which
they can’t do anything about (“Tainted” kernel notice in kernel crashes and oopses).
▶ See admin-guide/tainted-kernels for details about tainted flag values.
▶ Useful for users to check that their system is 100% free (for the kernel, check
/proc/sys/kernel/tainted; run vrms to check installed packages)
▶ Values
▶ GPL compatible (see include/linux/license.h: GPL, GPL v2,
GPL and additional rights, Dual MIT/GPL, Dual BSD/GPL, Dual MPL/GPL)
▶ Proprietary
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 117/470
Compiling a module
Two solutions
▶ Out of tree
▶ When the code is outside of the kernel source tree, in a different directory
▶ Advantage: Might be easier to handle than modifications to the kernel itself
▶ Drawbacks: Not integrated to the kernel configuration/compilation process, needs to
be built separately, the driver cannot be built statically
▶ Inside the kernel tree
▶ Well integrated into the kernel configuration/compilation process
▶ Driver can be built statically if needed
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 118/470
Compiling an out-of-tree module 1/2
▶ The below Makefile should be reusable for any single-file out-of-tree Linux
module
▶ The source file is hello.c
▶ Just run make to build the hello.ko file
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
KDIR := /path/to/kernel/sources
all:
<tab>$(MAKE) -C $(KDIR) M=$$PWD
endif
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 119/470
Compiling an out-of-tree module 2/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 121/470
New driver in kernel sources 1/2
config USB_SERIAL_NAVMAN
tristate "USB Navman GPS device"
depends on USB_SERIAL
help
To compile this driver as a module, choose M
here: the module will be called navman.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 122/470
New driver in kernel sources 2/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 123/470
Hello module with parameters 1/2
// SPDX-License-Identifier: GPL-2.0
/* hello_param.c */
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 124/470
Hello module with parameters 2/2
module_init(hello_init);
module_exit(hello_exit);
Thanks to Jonathan Corbet for the examples
Source code available on: https://github.com/bootlin/training-materials/blob/master/code/hello-param/hello_param.c
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 125/470
Declaring a module parameter
module_param(
name, /* name of an already defined variable */
type, /* standard types (different from C types) are:
* byte, short, ushort, int, uint, long, ulong
* charp: a character pointer
* bool: a bool, values 0/1, y/n, Y/N.
* invbool: the above, only sense-reversed (N = true). */
perm /* for /sys/module/<module_name>/parameters/<param>,
* 0: no such module parameter value file */
);
/* Example: drivers/block/loop.c */
static int max_loop;
module_param(max_loop, int, 0444);
MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
Modules parameter arrays are also possible with module_param_array().
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 126/470
Practical lab - Writing modules
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 127/470
Useful general-purpose kernel APIs
Useful general-purpose
kernel APIs
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 128/470
Memory/string utilities
▶ In include/linux/string.h
▶ Memory-related: memset(), memcpy(), memmove(), memscan(), memcmp(), memchr()
▶ String-related: strcpy(), strcat(), strcmp(), strchr(), strrchr(), strlen()
and variants
▶ Allocate and copy a string: kstrdup(), kstrndup()
▶ Allocate and copy a memory area: kmemdup()
▶ In include/linux/kernel.h
▶ String to int conversion: simple_strtoul(), simple_strtol(),
simple_strtoull(), simple_strtoll()
▶ Other string functions: sprintf(), sscanf()
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 129/470
Linked lists
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 130/470
Linked lists examples 1/2
From include/soc/at91/atmel_tcb.h
/*
* Definition of a list element, with a
* struct list_head member
*/
struct atmel_tc
{
/* some members */
struct list_head node;
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 131/470
Linked lists examples 2/2
From drivers/misc/atmel_tclib.c
/* Define the global list */
static LIST_HEAD(tc_list);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 132/470
Linux device and driver model
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 133/470
Linux device and driver model
Introduction
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 134/470
The need for a device model?
▶ The Linux kernel runs on a wide range of architectures and hardware platforms,
and therefore needs to maximize the reusability of code between platforms.
▶ For example, we want the same USB device driver to be usable on a x86 PC, or
an ARM platform, even though the USB controllers used on these platforms are
different.
▶ This requires a clean organization of the code, with the device drivers separated
from the controller drivers, the hardware description separated from the drivers
themselves, etc.
▶ This is what the Linux kernel Device Model allows, in addition to other
advantages covered in this section.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 135/470
Kernel and Device Drivers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 136/470
Device Model data structures
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 137/470
Bus Drivers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 138/470
Linux device and driver model
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 139/470
Example: USB Bus 1/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 140/470
Example: USB Bus 2/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 141/470
Example of Device Driver
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 142/470
Device Identifiers
▶ Defines the set of devices that this driver can manage, so that the USB core
knows for which devices this driver should be used
▶ The MODULE_DEVICE_TABLE() macro allows depmod (run by
make modules_install) to extract the relationship between device identifiers and
drivers, so that drivers can be loaded automatically by udev. See
/lib/modules/$(uname -r)/modules.{alias,usbmap}
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 143/470
Instantiation of usb_driver
▶ struct usb_driver is a structure defined by the USB core. Each USB device
driver must instantiate it, and register itself to the USB core using this structure
▶ This structure inherits from struct device_driver, which is defined by the
device model.
static struct usb_driver rtl8150_driver = {
.name = "rtl8150",
.probe = rtl8150_probe,
.disconnect = rtl8150_disconnect,
.id_table = rtl8150_table,
.suspend = rtl8150_suspend,
.resume = rtl8150_resume
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 144/470
Driver registration and unregistration
▶ When the driver is loaded / unloaded, it must register / unregister itself to / from the
USB core
▶ Done using usb_register() and usb_deregister(), provided by the USB core.
module_init(usb_rtl8150_init);
module_exit(usb_rtl8150_exit);
module_usb_driver(rtl8150_driver);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 145/470
At Initialization
▶ The USB adapter driver that corresponds to the USB controller of the system
registers itself to the USB core
▶ The rtl8150 USB device driver registers itself to the USB core
▶ The USB core now knows the association between the vendor/product IDs of
rtl8150 and the struct usb_driver structure of this driver
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 146/470
When a device is detected
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 147/470
Probe Method
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 148/470
Example: probe() and disconnect() methods
static int rtl8150_probe(struct usb_interface *intf, static void rtl8150_disconnect(struct usb_interface *intf)
const struct usb_device_id *id) {
{ rtl8150_t *dev = usb_get_intfdata(intf);
rtl8150_t *dev;
struct net_device *netdev; usb_set_intfdata(intf, NULL);
if (dev) {
netdev = alloc_etherdev(sizeof(rtl8150_t)); set_bit(RTL8150_UNPLUG, &dev->flags);
[...] tasklet_kill(&dev->tl);
dev = netdev_priv(netdev); unregister_netdev(dev->netdev);
tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev); unlink_all_urbs(dev);
spin_lock_init(&dev->rx_pool_lock); free_all_urbs(dev);
[...] free_skb_pool(dev);
netdev->netdev_ops = &rtl8150_netdev_ops; if (dev->rx_skb)
alloc_all_urbs(dev); dev_kfree_skb(dev->rx_skb);
[...] kfree(dev->intr_buff);
usb_set_intfdata(intf, dev); free_netdev(dev->netdev);
SET_NETDEV_DEV(netdev, &intf->dev); }
register_netdev(netdev); }
return 0;
}
Source: drivers/net/usb/rtl8150.c
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 149/470
The Model is Recursive
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 150/470
Linux device and driver model
Platform drivers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 151/470
Non-discoverable buses
▶ On embedded systems, devices are often not connected through a bus allowing
enumeration, hotplugging, and providing unique identifiers for devices.
▶ For example, the devices on I2C buses or SPI buses, or the devices directly part of
the system-on-chip.
▶ However, we still want all of these devices to be part of the device model.
▶ Such devices, instead of being dynamically detected, must be statically described
in either:
▶ The kernel source code
▶ The Device Tree, a hardware description file used on some architectures.
▶ BIOS ACPI tables (x86/PC architecture)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 152/470
Platform devices
▶ Amongst the non-discoverable devices, a huge family are the devices that are
directly part of a system-on-chip: UART controllers, Ethernet controllers, SPI or
I2C controllers, graphic or audio devices, etc.
▶ In the Linux kernel, a special bus, called the platform bus has been created to
handle such devices.
▶ It supports platform drivers that handle platform devices.
▶ It works like any other bus (USB, PCI), except that devices are enumerated
statically instead of being discovered dynamically.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 153/470
Implementation of a Platform Driver (1)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 154/470
Implementation of a Platform Driver (2)
module_init(imx_serial_init);
module_exit(imx_serial_cleanup);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 155/470
Platform Device Instantiation: old style (1/2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 156/470
Platform device instantiation: old style (2/2)
▶ And the list of devices was added to the system during board initialization
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 157/470
The Resource Mechanism
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 158/470
Declaring resources (old style)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 159/470
Using Resources (old style)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 160/470
platform_data Mechanism (old style)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 161/470
platform_data example 1/2
▶ The i.MX serial port driver defines the following structure to be passed through
struct platform_data
struct imxuart_platform_data {
int (*init)(struct platform_device *pdev);
void (*exit)(struct platform_device *pdev);
unsigned int flags;
void (*irda_enable)(int enable);
unsigned int irda_inv_rx:1;
unsigned int irda_inv_tx:1;
unsigned short transceiver_delay;
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 162/470
platform_data Example 2/2
▶ The uart_pdata structure was associated to the struct platform_device
structure in the MX1ADS board file (the real code was slightly more complicated)
struct platform_device mx1ads_uart1 = {
.name = "imx-uart",
.dev {
.platform_data = &uart_pdata,
},
.resource = imx_uart1_resources,
[...]
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 164/470
Device Tree example
uart0: serial@44e09000 {
compatible = "ti,omap3-uart";
ti,hwmods = "uart1";
clock-frequency = <48000000>;
reg = <0x44e09000 0x2000>;
interrupts = <72>;
status = "disabled";
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 165/470
Device Tree inheritance (1/2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 166/470
Device Tree inheritance (2/2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 167/470
Device Tree: compatible string
▶ With the device tree, a device is bound to the corresponding driver using the compatible
string.
▶ The of_match_table field of struct device_driver lists the compatible strings
supported by the driver. drivers/tty/serial/omap-serial.c example:
#if defined(CONFIG_OF)
static const struct of_device_id omap_serial_of_match[] = {
{ .compatible = "ti,omap2-uart" },
{ .compatible = "ti,omap3-uart" },
{ .compatible = "ti,omap4-uart" },
{},
};
MODULE_DEVICE_TABLE(of, omap_serial_of_match);
#endif
static struct platform_driver serial_omap_driver = {
.probe = serial_omap_probe,
.remove = serial_omap_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
.of_match_table = of_match_ptr(omap_serial_of_match),
},
};
▶ Note: the of_match_ptr() macro instantiates to NULL when CONFIG_OF is not set.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 168/470
Device Tree Resources
▶ The drivers will use the same mechanism that we saw previously to retrieve basic
information: interrupts numbers, physical addresses, etc.
▶ The available resources list will be built up by the kernel at boot time from the
device tree, so that you don’t need to make any unnecessary lookups to the DT
when loading your driver.
▶ Any additional information will be specific to a driver or the class it belongs to,
defining the bindings.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 169/470
Device Tree design principles
▶ Describe hardware (how the hardware is), not configuration (how I choose to
use the hardware)
▶ OS-agnostic
▶ For a given piece of HW, Device Tree should be the same for U-Boot, FreeBSD or
Linux
▶ There should be no need to change the Device Tree when updating the OS
▶ Describe integration of hardware components, not the internals of hardware
components
▶ The details of how a specific device/IP block is working is handled by code in device
drivers
▶ The Device Tree describes how the device/IP block is connected/integrated with the
rest of the system: IRQ lines, DMA channels, clocks, reset lines, etc.
▶ Like all beautiful design principles, these principles are sometimes violated.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 170/470
Device Tree specifications
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 171/470
Device Tree binding: old style
Documentation/devicetree/bindings/mtd/spear_smi.txt
smi: flash@fc000000 {
Required properties: compatible = "st,spear600-smi";
- compatible : "st,spear600-smi" #address-cells = <1>;
- reg : Address range of the mtd chip #size-cells = <1>;
- #address-cells, #size-cells : Must be present if the device has sub-nodes reg = <0xfc000000 0x1000>;
representing partitions. interrupt-parent = <&vic1>;
interrupts = <12>;
- interrupts: Should contain the STMMAC interrupts clock-rate = <50000000>; /* 50MHz */
- clock-rate : Functional clock rate of SMI in Hz
flash@f8000000 {
Optional properties: st,smi-fast-mode;
- st,smi-fast-mode : Flash supports read in fast mode ...
};
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 172/470
Device Tree binding: YAML style
Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml
maintainers: ...
- Pierre-Yves MORDRET <[email protected]>
clock-frequency:
properties: description: Desired I2C bus clock frequency in Hz. If not specified,
compatible: the default 100 kHz frequency will be used.
enum: For STM32F7, STM32H7 and STM32MP1 SoCs, if timing
- st,stm32f4-i2c parameters match, the bus clock frequency can be from
- st,stm32f7-i2c 1Hz to 1MHz.
- st,stm32mp15-i2c default: 100000
minimum: 1
reg: maximum: 1000000
maxItems: 1
required:
interrupts: - compatible
items: - reg
- description: interrupt ID for I2C event - interrupts
- description: interrupt ID for I2C error - resets
- clocks
resets:
maxItems: 1
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 173/470
Device Tree binding: YAML style example
examples:
- |
//Example 3 (with st,stm32mp15-i2c compatible on stm32mp)
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/stm32mp1-clks.h>
#include <dt-bindings/reset/stm32mp1-resets.h>
i2c@40013000 {
compatible = "st,stm32mp15-i2c";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x40013000 0x400>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc I2C2_K>;
resets = <&rcc I2C2_R>;
i2c-scl-rising-time-ns = <185>;
i2c-scl-falling-time-ns = <20>;
st,syscfg-fmp = <&syscfg 0x4 0x2>;
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 174/470
Validating Device Tree in Linux
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 175/470
sysfs
▶ The bus, device, drivers, etc. structures are internal to the kernel
▶ The sysfs virtual filesystem offers a mechanism to export such information to
user space
▶ Used for example by udev to provide automatic module loading, firmware loading,
mounting of external media, etc.
▶ sysfs is usually mounted in /sys
▶ /sys/bus/ contains the list of buses
▶ /sys/devices/ contains the list of devices
▶ /sys/class enumerates devices by the framework they are registered to (net,
input, block...), whatever bus they are connected to. Very useful!
▶ Take your time to explore /sys on your workstation.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 176/470
References
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 177/470
Introduction to the I2C subsystem
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 178/470
What is I2C?
▶ A very commonly used low-speed bus to connect on-board and external devices to
the processor.
▶ Uses only two wires: SDA for the data, SCL for the clock.
▶ It is a master/slave bus: only the master can initiate transactions, and slaves can
only reply to transactions initiated by masters.
▶ In a Linux system, the I2C controller embedded in the processor is typically the
master, controlling the bus.
▶ Each slave device is identified by an I2C address (you can’t have 2 devices with
the same address on the same bus). Each transaction initiated by the master
contains this address, which allows the relevant slave to recognize that it should
reply to this particular transaction.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 179/470
An I2C bus example
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 180/470
The I2C bus driver
▶ Like all bus subsystems, the I2C bus driver is responsible for:
▶ Providing an API to implement I2C controller drivers
▶ Providing an API to implement I2C device drivers, in kernel space
▶ Providing an API to implement I2C device drivers, in user space
▶ The core of the I2C bus driver is located in drivers/i2c/.
▶ The I2C controller drivers are located in drivers/i2c/busses/.
▶ The I2C device drivers are located throughout drivers/, depending on the
framework used to expose the devices (e.g. drivers/input/ for input devices).
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 181/470
Registering an I2C device driver
▶ Like all bus subsystems, the I2C subsystem defines a struct i2c_driver that
inherits from struct device_driver, and which must be instantiated and
registered by each I2C device driver.
▶ As usual, this structure points to the ->probe() and ->remove() functions.
▶ It also contains an id_table, used for non-DT based probing of I2C devices.
▶ A ->probe_new() function can replace ->probe() when no id_table is provided.
▶ The i2c_add_driver() and i2c_del_driver() functions are used to
register/unregister the driver.
▶ If the driver doesn’t do anything else in its init()/exit() functions, it is advised
to use the module_i2c_driver() macro instead.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 182/470
Registering an I2C device driver: example
static const struct i2c_device_id adxl345_i2c_id[] = {
{ "adxl345", ADXL345 },
{ "adxl375", ADXL375 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id);
MODULE_DEVICE_TABLE(of, adxl345_of_match);
module_i2c_driver(adxl345_i2c_driver);
From drivers/iio/accel/adxl345_i2c.c
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 183/470
Registering an I2C device: non-DT
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 184/470
Registering an I2C device, non-DT example
...
i2c_register_board_info(0, em7210_i2c_devices,
ARRAY_SIZE(em7210_i2c_devices));
}
From arch/arm/mach-iop32x/em7210.c
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 185/470
Registering an I2C device, in the DT
▶ In the Device Tree, the I2C controller device is typically defined in the .dtsi file
that describes the processor.
▶ Normally defined with status = "disabled".
▶ At the board/platform level:
▶ the I2C controller device is enabled (status = "okay")
▶ the I2C bus frequency is defined, using the clock-frequency property.
▶ the I2C devices on the bus are described as children of the I2C controller node,
where the reg property gives the I2C slave address on the bus.
▶ See the binding for the corresponding driver for a specification of the expected DT
properties. Example: Documentation/devicetree/bindings/i2c/i2c-omap.txt
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 186/470
Registering an I2C device, DT example (1/2)
From arch/arm/boot/dts/sun7i-a20.dtsi
axp209: pmic@34 {
compatible = "x-powers,axp209";
reg = <0x34>;
interrupt-parent = <&nmi_intc>;
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
interrupt-controller;
#interrupt-cells = <1>;
};
};
From arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 188/470
probe_new() / probe() and remove()
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 189/470
Probe example
From drivers/iio/accel/da311.c
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 190/470
Remove example
From drivers/iio/accel/da311.c
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 191/470
Practical lab - Linux device model for an I2C driver
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 192/470
Communicating with the I2C device: raw API
The most basic API to communicate with the I2C device provides functions to either
send or receive data:
▶ int i2c_master_send(const struct i2c_client *client, const char
*buf, int count);
Sends the contents of buf to the client.
▶ int i2c_master_recv(const struct i2c_client *client, char *buf, int
count);
Receives count bytes from the client, and store them into buf.
Both functions return a negative error number in case of failure, otherwise the number
of transmitted bytes.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 193/470
Communicating with the I2C device: message transfer
The message transfer API allows to describe transfers that consists of several
messages, with each message being a transaction in one direction:
▶ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int
num);
▶ The struct i2c_adapter pointer can be found by using client->adapter
▶ The struct i2c_msg structure defines the length, location, and direction of the
message.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 194/470
I2C: message transfer example
msg[1].addr = ts->client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = ts->read_buf_len;
msg[1].buf = buf;
From drivers/input/touchscreen/st1232.c
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 195/470
SMBus calls
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 196/470
List of SMBus functions
▶ Write a command byte, and read or write a block of data (max 32 bytes)
▶ s32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values);
▶ s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values);
▶ Write a command byte, and read or write a block of data (no limit)
▶ s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, u8 *values);
▶ s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 197/470
I2C functionality
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 198/470
References
Introduction to pin
muxing
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 200/470
What is pin muxing?
▶ Modern SoCs (System on Chip) include more and more hardware blocks, many of
which need to interface with the outside world using pins.
▶ However, the physical size of the chips remains small, and therefore the number of
available pins is limited.
▶ For this reason, not all of the internal hardware block features can be exposed on
the pins simultaneously.
▶ The pins are multiplexed: they expose either the functionality of hardware block
A or the functionality of hardware block B.
▶ This multiplexing is usually software configurable.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 201/470
Pin muxing diagram
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 202/470
Pin muxing in the Linux kernel
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 203/470
pinctrl subsystem diagram
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 204/470
Device Tree properties for consumer devices
The devices that require certains pins to be muxed will use the pinctrl-<x> and
pinctrl-names Device Tree properties.
▶ The pinctrl-0, pinctrl-1, pinctrl-<x> properties link to a pin configuration
for a given state of the device.
▶ The pinctrl-names property associates a name to each state. The name
default is special, and is automatically selected by a device driver, without
having to make an explicit pinctrl function call.
▶ See Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt for
details.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 205/470
Device Tree properties for consumer devices - Examples
i2c0: i2c@f8014000 {
i2c0: i2c@11000 {
...
...
pinctrl-names = "default", "gpio";
pinctrl-0 = <&pmx_twsi0>;
pinctrl-0 = <&pinctrl_i2c0>;
pinctrl-names = "default";
pinctrl-1 = <&pinctrl_i2c0_gpio>;
...
...
};
};
Most common case
Case with multiple pin states
(arch/arm/boot/dts/kirkwood.dtsi)
(arch/arm/boot/dts/sama5d4.dtsi)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 206/470
Defining pinctrl configurations
▶ The different pinctrl configurations must be defined as child nodes of the main
pinctrl device (which controls the muxing of pins).
▶ The configurations may be defined at:
▶ the SoC level (.dtsi file), for pin configurations that are often shared between
multiple boards
▶ at the board level (.dts file) for configurations that are board specific.
▶ The pinctrl-<x> property of the consumer device points to the pin configuration
it needs through a DT phandle.
▶ The description of the configurations is specific to each pinctrl driver. See
Documentation/devicetree/bindings/pinctrl for the pinctrl bindings.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 207/470
Example on OMAP/AM33xx
&am33xx_pinmux {
...
i2c2_pins: pinmux_i2c2_pins {
▶ On OMAP/AM33xx, the pinctrl-single pinctrl-single,pins = <
AM33XX_IOPAD(0x978, PIN_INPUT_PULLUP | MUX_MODE3)
driver is used. It is common between multiple /* (D18) uart1_ctsn.I2C2_SDA */
AM33XX_IOPAD(0x97c, PIN_INPUT_PULLUP | MUX_MODE3)
SoCs and simply allows to configure pins by /* (D17) uart1_rtsn.I2C2_SCL */
>;
writing a value to a register. };
▶ In each pin configuration, a };
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 208/470
Example on the Allwinner A20 SoC
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 209/470
Illustration: live pin muxing configuration
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 211/470
Kernel frameworks for device drivers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 212/470
Kernel and Device Drivers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 213/470
Kernel frameworks for device drivers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 214/470
Types of devices
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 215/470
Major and minor numbers
▶ Within the kernel, all block and character devices are identified using a major and
a minor number.
▶ The major number typically indicates the family of the device.
▶ The minor number allows drivers to distinguish the various devices they manage.
▶ Most major and minor numbers are statically allocated, and identical across all
Linux systems.
▶ They are defined in admin-guide/devices.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 216/470
Devices: everything is a file
▶ A very important UNIX design decision was to represent most system objects as
files
▶ It allows applications to manipulate all system objects with the normal file API
(open, read, write, close, etc.)
▶ So, devices had to be represented as files to the applications
▶ This is done through a special artifact called a device file
▶ It is a special type of file, that associates a file name visible to user space
applications to the triplet (type, major, minor) that the kernel understands
▶ All device files are by convention stored in the /dev directory
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 217/470
Device files examples
Example of device files in a Linux system
Example C code that uses the usual file API to write data to a serial port
int fd;
fd = open("/dev/ttyS0", O_RDWR);
write(fd, "Hello", 5);
close(fd);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 218/470
Creating device files
▶ Before Linux 2.6.32, on basic Linux systems, the device files had to be created
manually using the mknod command
▶ mknod /dev/<device> [c|b] major minor
▶ Needed root privileges
▶ Coherency between device files and devices handled by the kernel was left to the
system developer
▶ The devtmpfs virtual filesystem can be mounted on /dev and contains all the
devices registered to kernel frameworks. The CONFIG_DEVTMPFS_MOUNT kernel
configuration option makes the kernel mount it automatically at boot time, except
when booting on an initramfs.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 219/470
Kernel frameworks for device drivers
Character drivers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 220/470
A character driver in the kernel
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 221/470
From user space to the kernel: character devices
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 222/470
File operations
Here are the most important operations for a character driver, from the definition of
struct file_operations:
struct file_operations {
struct module *owner;
ssize_t (*read) (struct file *, char __user *,
size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *,
size_t, loff_t *);
long (*unlocked_ioctl) (struct file *, unsigned int,
unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
...
};
Many more operations exist. All of them are optional.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 223/470
open() and release()
▶ ssize_t foo_read(struct file *f, char __user *buf, size_t sz, loff_t *off)
▶ Called when user space uses the read() system call on the device.
▶ Must read data from the device, write at most sz bytes to the user space buffer buf,
and update the current position in the file off. f is a pointer to the same file
structure that was passed in the open() operation
▶ Must return the number of bytes read.
0 is usually interpreted by userspace as the end of the file.
▶ On UNIX, read() operations typically block when there isn’t enough data to read
from the device
▶ ssize_t foo_write(struct file *f, const char __user *buf, size_t sz, loff_t *off)
▶ Called when user space uses the write() system call on the device
▶ The opposite of read, must read at most sz bytes from buf, write it to the device,
update off and return the number of bytes written.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 225/470
Exchanging data with user space 1/3
▶ Kernel code isn’t allowed to directly access user space memory, using memcpy() or
direct pointer dereferencing
▶ Doing so does not work on some architectures
▶ If the address passed by the application was invalid, the application would segfault.
▶ Never trust user space. A malicious application could pass a kernel address which
you could overwrite with device data (read case), or which you could dump to the
device (write case).
▶ To keep the kernel code portable, secure, and have proper error handling, your
driver must use special kernel functions to exchange data with user space.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 226/470
Exchanging data with user space 2/3
▶ A single value
▶ get_user(v, p);
▶ The kernel variable v gets the value pointed by the user space pointer p
▶ put_user(v, p);
▶ The value pointed by the user space pointer p is set to the contents of the kernel
variable v.
▶ A buffer
▶ unsigned long copy_to_user(void __user *to,
const void *from, unsigned long n);
▶ unsigned long copy_from_user(void *to,
const void __user *from, unsigned long n);
▶ The return value must be checked. Zero on success, non-zero on failure. If
non-zero, the convention is to return -EFAULT.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 227/470
Exchanging data with user space 3/3
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 228/470
Zero copy access to user memory
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 229/470
unlocked_ioctl()
▶ long unlocked_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
▶ Associated to the ioctl() system call.
▶ Called unlocked because it didn’t hold the Big Kernel Lock (gone now).
▶ Allows to extend the driver capabilities beyond the limited read/write API.
▶ For example: changing the speed of a serial port, setting video output format,
querying a device serial number... Used extensively in the V4L2 (video) and ALSA
(sound) driver frameworks.
▶ cmd is a number identifying the operation to perform.
See driver-api/ioctl for the recommended way of choosing cmd numbers.
▶ arg is the optional argument passed as third argument of the ioctl() system call.
Can be an integer, an address, etc.
▶ The semantic of cmd and arg is driver-specific.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 230/470
ioctl() example: kernel side
#include <linux/phantom.h>
switch (cmd) {
case PHN_SET_REG:
if (copy_from_user(&r, argp, sizeof(r)))
return -EFAULT;
/* Do something */
break;
...
case PHN_GET_REG:
if (copy_to_user(argp, &r, sizeof(r)))
return -EFAULT;
/* Do something */
break;
...
default:
return -ENOTTY;
}
return 0;
}
#include <linux/phantom.h>
int main(void)
{
int fd, ret;
struct phm_reg reg;
fd = open("/dev/phantom");
assert(fd > 0);
reg.field1 = 42;
reg.field2 = 67;
return 0;
}
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 232/470
Kernel frameworks for device drivers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 233/470
Beyond character drivers: kernel frameworks
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 234/470
Kernel Frameworks
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 235/470
Example: Framebuffer Framework
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 236/470
Framebuffer driver operations
Here are the operations a framebuffer driver can or must implement, and define them in a
struct fb_ops structure (excerpt from drivers/video/fbdev/skeletonfb.c)
static struct fb_ops xxxfb_ops = {
.owner = THIS_MODULE,
.fb_open = xxxfb_open,
.fb_read = xxxfb_read,
.fb_write = xxxfb_write,
.fb_release = xxxfb_release,
.fb_check_var = xxxfb_check_var,
.fb_set_par = xxxfb_set_par,
.fb_setcolreg = xxxfb_setcolreg,
.fb_blank = xxxfb_blank,
.fb_pan_display = xxxfb_pan_display,
.fb_fillrect = xxxfb_fillrect, /* Needed !!! */
.fb_copyarea = xxxfb_copyarea, /* Needed !!! */
.fb_imageblit = xxxfb_imageblit, /* Needed !!! */
.fb_cursor = xxxfb_cursor, /* Optional !!! */
.fb_rotate = xxxfb_rotate,
.fb_sync = xxxfb_sync,
.fb_ioctl = xxxfb_ioctl,
.fb_mmap = xxxfb_mmap,
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 237/470
Framebuffer driver code
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 238/470
Kernel frameworks for device drivers
Device-managed allocations
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 239/470
Device managed allocations
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 240/470
Device managed allocations: memory allocation example
▶ Normally done with kmalloc(size_t, gfp_t), released with kfree(void *)
▶ Device managed with devm_kmalloc(struct device *, size_t, gfp_t)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 241/470
Kernel frameworks for device drivers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 242/470
Driver-specific Data Structure
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 243/470
Driver-specific Data Structure Examples 1/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 244/470
Driver-specific Data Structure Examples 2/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 245/470
Links between structures 1/4
▶ The framework structure typically contains a struct device * pointer that the
driver must point to the corresponding struct device
▶ It’s the relationship between the logical device (for example a network interface) and
the physical device (for example the USB network adapter)
▶ The device structure also contains a void * pointer that the driver can freely use.
▶ It’s often used to link back the device to the higher-level structure from the
framework.
▶ It allows, for example, from the struct platform_device structure, to find the
structure describing the logical device
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 246/470
Links between structures 2/4
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 247/470
Links between structures 3/4
[...]
[...]
ds1305->rtc = devm_rtc_allocate_device(&spi->dev);
// Arrows 3 and 4
[...]
}
[...]
}
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 248/470
Links between structures 4/4
static int rtl8150_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
rtl8150_t *dev;
struct net_device *netdev;
netdev = alloc_etherdev(sizeof(rtl8150_t));
dev = netdev_priv(netdev);
[...]
[...]
[...]
}
[...]
}
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 249/470
The input subsystem
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 250/470
What is the input subsystem?
▶ The input subsystem takes care of all the input events coming from the human
user.
▶ Initially written to support the USB HID (Human Interface Device) devices, it
quickly grew up to handle all kinds of inputs (using USB or not): keyboards, mice,
joysticks, touchscreens, etc.
▶ The input subsystem is split in two parts:
▶ Device drivers: they talk to the hardware (for example via USB), and provide
events (keystrokes, mouse movements, touchscreen coordinates) to the input core
▶ Event handlers: they get events from drivers and pass them where needed via
various interfaces (most of the time through evdev)
▶ In user space it is usually used by the graphic stack such as X.Org, Wayland or
Android’s InputManager.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 251/470
Input subsystem diagram
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 252/470
Input subsystem overview
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 253/470
Input subsystem API 1/3
An input device is described by a very long struct input_dev structure, an excerpt is:
struct input_dev {
const char *name;
[...]
struct input_id id;
[...]
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
[...]
int (*getkeycode)(struct input_dev *dev,
struct input_keymap_entry *ke);
[...]
int (*open)(struct input_dev *dev);
[...]
int (*event)(struct input_dev *dev, unsigned int type,
unsigned int code, int value);
[...]
};
Before being used, this structure must be allocated and initialized, typically with:
struct input_dev *devm_input_allocate_device(struct device *dev);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 254/470
Input subsystem API 2/3
▶ Depending on the type of events that will be generated, the input bit fields evbit
and keybit must be configured: For example, for a button we only generate
EV_KEY type events, and from these only BTN_0 events code:
set_bit(EV_KEY, myinput_dev.evbit);
set_bit(BTN_0, myinput_dev.keybit);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 255/470
Input subsystem API 3/3
The events are sent by the driver to the event handler using input_event(struct
input_dev *dev, unsigned int type, unsigned int code, int value);
▶ The event types are documented in input/event-codes
▶ An event is composed by one or several input data changes (packet of input data
changes) such as the button state, the relative or absolute position along an axis,
etc..
▶ After submitting potentially multiple events, the input core must be notified by
calling: void input_sync(struct input_dev *dev):
▶ The input subsystem provides other wrappers such as input_report_key(),
input_report_abs(), ...
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 256/470
Example from drivers/hid/usbhid/usbmouse.c
input_sync(dev);
...
}
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 257/470
Polling input devices
▶ The input subsystem provides an API to support simple input devices that do not
raise interrupts but have to be periodically scanned or polled to detect changes in
their state.
▶ Setting up polling is done using input_setup_polling():
int input_setup_polling(struct input_dev *dev, void (*poll_fn)
(struct input_dev *dev));
▶ poll_fn is the function that will be called periodically.
▶ The polling interval can be set using input_set_poll_interval() or
input_set_min_poll_interval() and input_set_max_poll_interval()
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 258/470
evdev user space interface
▶ The main user space interface to input devices is the event interface
▶ Each input device is represented as a /dev/input/event<X> character device
▶ A user space application can use blocking and non-blocking reads, but also
select() (to get notified of events) after opening this device.
▶ Each read will return struct input_event structures of the following format:
struct input_event {
struct timeval time;
unsigned short type;
unsigned short code;
unsigned int value;
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 259/470
Practical lab - Expose the Nunchuk to user space
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 260/470
Memory Management
Memory Management
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 261/470
Physical and virtual memory
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 262/470
Virtual memory organization (on 32 bit)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 263/470
Physical / virtual memory mapping (on 32 bit)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 264/470
Accessing more physical memory on 32 bit
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 265/470
Notes on user space memory
▶ New user space memory is allocated either from the already allocated process
memory, or using the mmap system call
▶ Note that memory allocated may not be physically allocated:
▶ Kernel uses demand fault paging to allocate the physical page (the physical page is
allocated when access to the virtual address generates a page fault)
▶ ... or may have been swapped out, which also induces a page fault
▶ User space memory allocation is allowed to over-commit memory (more than
available physical memory) ⇒ can lead to out of memory
▶ OOM killer kicks in and selects a process to kill to retrieve some memory. That’s
better than letting the system freeze.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 266/470
Allocators in the kernel
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 267/470
Page allocator
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 268/470
Page allocator API: get free pages
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 269/470
Page allocator API: free pages
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 270/470
Page allocator flags
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 271/470
SLAB allocator 1/2
▶ The SLAB allocator allows to create caches, which contain a set of objects of the
same size. In English, slab means tile.
▶ The object size can be smaller or greater than the page size
▶ The SLAB allocator takes care of growing or reducing the size of the cache as
needed, depending on the number of allocated objects. It uses the page allocator
to allocate and free pages.
▶ SLAB caches are used for data structures that are present in many instances in
the kernel: directory entries, file objects, network packet descriptors, process
descriptors, etc.
▶ See /proc/slabinfo
▶ They are rarely used for individual drivers.
▶ See include/linux/slab.h for the API
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 272/470
SLAB allocator 2/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 273/470
Different SLAB allocators
There are three different, but API compatible, implementations of a SLAB allocator in the
Linux kernel. A particular implementation is chosen at configuration time.
▶ SLAB: legacy, well proven allocator.
Linux 5.10 on arm (32 bit): used in 39 defconfig files
▶ SLOB: much simpler. More space efficient but doesn’t scale well.
Can save space in small systems (depends on CONFIG_EXPERT).
Linux 5.10 on arm (32 bit): used in 7 defconfig files
Results on BeagleBone Black: -5 KB compressed kernel size, +1.43 s boot time!
▶ SLUB: more recent and simpler than SLAB, scaling much better (in particular for huge
systems) and creating less fragmentation. Now the default allocator.
Linux 5.10 on arm (32 bit): used in 9 defconfig files
Results on BeagleBone Black: +4 KB compressed kernel, + 2ms total boot time.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 274/470
kmalloc allocator
▶ The kmalloc allocator is the general purpose memory allocator in the Linux kernel
▶ For small sizes, it relies on generic SLAB caches, named kmalloc-XXX in
/proc/slabinfo
▶ For larger sizes, it relies on the page allocator
▶ The allocated area is guaranteed to be physically contiguous
▶ The allocated area size is rounded up to the size of the smallest SLAB cache in
which it can fit (while using the SLAB allocator directly allows to have more
flexibility)
▶ It uses the same flags as the page allocator (GFP_KERNEL, GFP_ATOMIC, GFP_DMA,
etc.) with the same semantics.
▶ Maximum sizes, on x86 and arm (see https://j.mp/YIGq6W):
- Per allocation: 4 MB
- Total allocations: 128 MB
▶ Should be used as the primary allocator unless there is a strong reason to use
another one.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 275/470
kmalloc API 1/2
▶ #include <linux/slab.h>
▶ void *kmalloc(size_t size, int flags);
▶ Allocate size bytes, and return a pointer to the area (virtual address)
▶ size: number of bytes to allocate
▶ flags: same flags as the page allocator
▶ void kfree(const void *objp);
▶ Free an allocated area
▶ Example: (drivers/infiniband/core/cache.c)
struct ib_update_work *work;
work = kmalloc(sizeof(*work), GFP_ATOMIC);
...
kfree(work);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 276/470
kmalloc API 2/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 277/470
devm_ kmalloc functions
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 278/470
vmalloc allocator
▶ The vmalloc() allocator can be used to obtain memory zones that are contiguous
in the virtual addressing space, but not made out of physically contiguous pages.
The requested memory size is rounded up to the next page.
▶ The allocated area is in the kernel space part of the address space, but outside of
the identically-mapped area
▶ Allocations of fairly large areas is possible (almost as big as total available
memory, see https://j.mp/YIGq6W again), since physical memory fragmentation
is not an issue, but areas cannot be used for DMA, as DMA usually requires
physically contiguous buffers.
▶ Example use: to allocate kernel buffers to load module code.
▶ API in include/linux/vmalloc.h
▶ void *vmalloc(unsigned long size);
▶ Returns a virtual address
▶ void vfree(void *addr);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 279/470
Kernel memory debugging
KASAN and Kmemleak have a significant overhead. Only use them in development!
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 280/470
Kernel memory management: resources
Virtual memory and Linux, Alan Ott and Matt Porter, 2016
Great and much more complete presentation about this topic
https://bit.ly/2Af1G2i (video: https://bit.ly/2Bwwv0C)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 281/470
I/O Memory
I/O Memory
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 282/470
Memory-Mapped I/O
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 283/470
Requesting I/O memory
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 284/470
/proc/iomem example - ARM 32 bit (BeagleBone Black, Linux 5.11)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 285/470
Mapping I/O memory in virtual memory
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 286/470
ioremap()
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 288/470
Accessing MMIO devices
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 290/470
/dev/mem
▶ Used to provide user space applications with direct access to physical addresses.
▶ Usage: open /dev/mem and read or write at given offset. What you read or write
is the value at the corresponding physical address.
▶ Used by applications such as the X server to write directly to device memory.
▶ On x86, arm, arm64, riscv, powerpc, parisc, s390: CONFIG_STRICT_DEVMEM
option to restrict /dev/mem to non-RAM addresses, for security reasons (Linux
5.12 status). CONFIG_IO_STRICT_DEVMEM goes beyond and only allows to access
idle I/O ranges (not appearing in /proc/iomem).
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 291/470
Practical lab - I/O memory and ports
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 292/470
The misc subsystem
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 293/470
Why a misc subsystem?
▶ The kernel offers a large number of frameworks covering a wide range of device
types: input, network, video, audio, etc.
▶ These frameworks allow to factorize common functionality between drivers and offer
a consistent API to user space applications.
▶ However, there are some devices that really do not fit in any of the existing
frameworks.
▶ Highly customized devices implemented in a FPGA, or other weird devices for which
implementing a complete framework is not useful.
▶ The drivers for such devices could be implemented directly as raw character
drivers (with cdev_init() and cdev_add()).
▶ But there is a subsystem that makes this work a little bit easier: the misc
subsystem.
▶ It is really only a thin layer above the character driver API.
▶ Another advantage is that devices are integrated in the Device Model (device files
appearing in devtmpfs, which you don’t have with raw character devices).
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 294/470
Misc subsystem diagram
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 295/470
Misc subsystem API (1/2)
▶ The misc subsystem API mainly provides two functions, to register and unregister
a single misc device:
▶ int misc_register(struct miscdevice * misc);
▶ void misc_deregister(struct miscdevice *misc);
▶ A misc device is described by a struct miscdevice structure:
struct miscdevice {
int minor;
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
const char *nodename;
umode_t mode;
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 296/470
Misc subsystem API (2/2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 297/470
User space API for misc devices
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 298/470
Practical lab - Output-only serial port driver
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 299/470
Processes, scheduling and interrupts
Processes, scheduling
and interrupts
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 300/470
Processes, scheduling and interrupts
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 301/470
Process, thread?
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 302/470
Process, thread: kernel point of view
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 303/470
Relation between execution mode, address space and context
▶ When speaking about process and thread, these concepts need to be clarified:
▶ Mode is the level of privilege allowing to perform some operations:
▶ Kernel Mode: in this level CPU can perform any operation allowed by its architecture;
any instruction, any I/O operation, any area of memory accessed.
▶ User Mode: in this level, certain instructions are not permitted (especially those that
could alter the global state of the machine), some memory areas cannot be accessed.
▶ Linux splits its address space in kernel space and user space
▶ Kernel space is reserved for code running in Kernel Mode.
▶ User space is the place were applications execute (accessible from Kernel Mode).
▶ Context represents the current state of an execution flow.
▶ The process context can be seen as the content of the registers associated to this
process: execution register, stack register...
▶ The interrupt context replaces the process context when the interrupt handler is
executed.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 304/470
A thread life
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 305/470
Execution of system calls
The execution of system calls takes place in the context of the thread requesting them.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 306/470
Processes, scheduling and interrupts
Sleeping
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 307/470
Sleeping
Sleeping is needed when a process (user space or kernel space) is waiting for data.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 308/470
How to sleep with a wait queue 1/3
▶ Must declare a wait queue, which will be used to store the list of threads waiting
for an event
▶ Dynamic queue declaration:
▶ Typically one queue per device managed by the driver
▶ It’s convenient to embed the wait queue inside a per-device data structure.
▶ Example from drivers/net/ethernet/marvell/mvmdio.c:
struct orion_mdio_dev {
...
wait_queue_head_t smi_busy_wait;
};
struct orion_mdio_dev *dev;
...
init_waitqueue_head(&dev->smi_busy_wait);
▶ Static queue declaration:
▶ Using a global variable when a global resource is sufficient
▶ DECLARE_WAIT_QUEUE_HEAD(module_queue);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 309/470
How to sleep with a waitqueue 2/3
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 310/470
How to sleep with a waitqueue 3/3
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 311/470
How to sleep with a waitqueue - Example
sig = wait_event_interruptible(ibmvtpm->wq,
!ibmvtpm->tpm_processing_cmd);
if (sig)
return -EINTR;
From char/tpm/tpm_ibmvtpm.c
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 312/470
Waking up!
Typically done by interrupt handlers when data sleeping processes are waiting for
become available.
▶ wake_up(&queue);
▶ Wakes up all processes in the wait queue
▶ wake_up_interruptible(&queue);
▶ Wakes up all processes waiting in an interruptible sleep on the given queue
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 313/470
Exclusive vs. non-exclusive
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 314/470
Sleeping and waking up - Implementation
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 315/470
How to sleep with completions 1/2
▶ Use wait_for_completion() when no particular condition must be enforced at
the time of the wake-up
▶ Leverages the power of wait queues
▶ Simplifies its use
▶ Highly efficient using low level scheduler facilities
▶ Preparation of the completion structure:
▶ Static declaration and initialization:
DECLARE_COMPLETION(setup_done);
▶ Dynamic declaration:
init_completion(&object->setup_done);
▶ The completion object should get a meaningful name (eg. not just “done”).
▶ Ready to be used by signal consumers and providers as soon as the completion
object is initialized
▶ See include/linux/completion.h for the full API
▶ Internal documentation at scheduler/completion.rst
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 316/470
How to sleep with completions 2/2
▶ Enter a wait state with
void wait_for_completion(struct completion *done)
▶ All wait_event() flavors are also supported, such as:
wait_for_completion_timeout(),
wait_for_completion_interruptible\{,_timeout\}(),
wait_for_completion_killable\{,_timeout\}(), etc
▶ Wake up consumers with
void complete(struct completion *done)
▶ Several calls to complete() are valid, they will wake up the same number of threads
waiting on this object (acts as a FIFO).
▶ A single complete_all() call would wake up all present and future threads waiting
on this completion object
▶ Reset the counter with
void reinit_completion(struct completion *done)
▶ Resets the number of “done” completions still pending
▶ Mind not to call init_completion() twice, which could confuse the enqueued tasks
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 317/470
Waiting when there is no interrupt
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 318/470
Waiting when hardware is involved
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 319/470
Processes, scheduling and interrupts
Interrupt Management
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 320/470
Registering an interrupt handler 1/2
The managed API is recommended:
int devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler,
unsigned long irq_flags, const char *devname, void *dev_id);
▶ device for automatic freeing at device or module release time.
▶ irq is the requested IRQ channel. For platform devices, use platform_get_irq()
to retrieve the interrupt number.
▶ handler is a pointer to the IRQ handler function
▶ irq_flags are option masks (see next slide)
▶ devname is the registered name (for /proc/interrupts). For platform drivers,
good idea to use pdev->name which allows to distinguish devices managed by the
same driver (example: 44e0b000.i2c).
▶ dev_id is an opaque pointer. It can typically be used to pass a pointer to a
per-device data structure. It cannot be NULL as it is used as an identifier for
freeing interrupts on a shared line.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 321/470
Releasing an interrupt handler
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 322/470
Registering an interrupt handler 2/2
Here are the most frequent irq_flags bit values in drivers (can be combined):
▶ IRQF_SHARED: interrupt channel can be shared by several devices.
▶ When an interrupt is received, all the interrupt handlers registered on the same
interrupt line are called.
▶ This requires a hardware status register telling whether an IRQ was raised or not.
▶ IRQF_ONESHOT: for use by threaded interrupts (see next slides). Keeping the
interrupt line disabled until the thread function has run.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 323/470
Interrupt handler constraints
▶ No guarantee in which address space the system will be in when the interrupt
occurs: can’t transfer data to and from user space.
▶ Interrupt handler execution is managed by the CPU, not by the scheduler.
Handlers can’t run actions that may sleep, because there is nothing to resume
their execution. In particular, need to allocate memory with GFP_ATOMIC.
▶ Interrupt handlers are run with all interrupts disabled on the local CPU (see
https://lwn.net/Articles/380931). Therefore, they have to complete their job
quickly enough, to avoiding blocking interrupts for too long.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 324/470
/proc/interrupts on Raspberry Pi 2 (ARM, Linux 4.19)
Note: interrupt numbers shown on the left-most column are virtual numbers when the Device Tree is
used. The physical interrupt numbers can be found in /sys/kernel/debug/irq/irqs/<nr> files when
CONFIG_GENERIC_IRQ_DEBUGFS=y.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 325/470
Interrupt handler prototype
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 326/470
Typical interrupt handler’s job
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 327/470
Threaded interrupts
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 328/470
Top half and bottom half processing
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 329/470
Top half and bottom half diagram
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 330/470
Softirqs
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 331/470
Example usage of softirqs - NAPI
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 332/470
Tasklets
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 333/470
Tasklet example: drivers/crypto/atmel-sha.c 1/2
/* The tasklet function */
static void atmel_sha_done_task(unsigned long data)
{
struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
[...]
}
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 334/470
Tasklet example: drivers/crypto/atmel-sha.c 2/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 335/470
Workqueues
▶ Workqueues are a general mechanism for deferring work. It is not limited in usage
to handling interrupts. It can typically be used for background work which can be
scheduled.
▶ The function registered as workqueue is executed in a thread, which means:
▶ All interrupts are enabled
▶ Sleeping is allowed
▶ A workqueue, usually allocated in a per-device structure, is registered with
INIT_WORK() and typically triggered with queue_work() when using a dedicated
queue or schedule_work() when using the default queue
▶ The complete API, in include/linux/workqueue.h, provides many other
possibilities (creating its own workqueue threads, etc.)
▶ Example (drivers/crypto/atmel-i2c):
INIT_WORK(&work_data->work, atmel_i2c_work_handler);
schedule_work(&work_data->work);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 336/470
Interrupt management summary
▶ Device driver
▶ In the probe() function, for each device, use devm_request_irq() to register an
interrupt handler for the device’s interrupt channel.
▶ Interrupt handler
▶ Called when an interrupt is raised.
▶ Acknowledge the interrupt
▶ If needed, schedule a per-device tasklet taking care of handling data.
▶ Wake up processes waiting for the data on a per-device queue
▶ Device driver
▶ In the remove() function, for each device, the interrupt handler is automatically
unregistered.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 337/470
Practical lab - Interrupts
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 338/470
Concurrent Access to Resources: Locking
Concurrent Access to
Resources: Locking
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 339/470
Sources of concurrency issues
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 340/470
Concurrency protection with locks
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 341/470
Linux mutexes
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 342/470
Locking and unlocking mutexes 1/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 343/470
Locking and unlocking mutexes 2/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 344/470
Spinlocks
▶ Locks to be used for code that is not allowed to sleep (interrupt handlers), or that
doesn’t want to sleep (critical sections). Be very careful not to call functions
which can sleep!
▶ Originally intended for multiprocessor systems
▶ Spinlocks never sleep and keep spinning in a loop until the lock is available.
▶ The critical section protected by a spinlock is not allowed to sleep.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 345/470
Initializing spinlocks
▶ Statically (unusual)
▶ DEFINE_SPINLOCK(my_lock);
▶ Dynamically (the usual case, on a per-device basis)
▶ void spin_lock_init(spinlock_t *lock);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 346/470
Using spinlocks 1/3
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 347/470
Using spinlocks 2/3
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 348/470
Using spinlocks 3/3
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 349/470
Spinlock example
▶ From drivers/tty/serial/uartlite.c
▶ Spinlock structure embedded into struct uart_port
struct uart_port {
spinlock_t lock;
/* Other fields */
};
▶ Spinlock taken/released with protection against interrupts
spin_lock_irqsave(&port->lock, flags);
/* Do something */
spin_unlock_irqrestore(&port->lock, flags);
}
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 350/470
More deadlock situations
They can lock up your system. Make sure they never happen!
Rule 1: don’t call a function that can try to Rule 2: if you need multiple locks, always
get access to the same lock acquire them in the same order!
Deadlock!
Deadlock!
Wait for Lock 1
Get Lock 2 Get Lock 1
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 351/470
Debugging locking and concurrency issues
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 352/470
Alternatives to locking
As we have just seen, locking can have a strong negative impact on system
performance. In some situations, you could do without it.
▶ By using lock-free algorithms like Read Copy Update (RCU).
▶ RCU API available in the kernel (See
https://en.wikipedia.org/wiki/Read-copy-update).
▶ When available, use atomic operations.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 353/470
Atomic variables 1/2
▶ Useful when the shared resource is an integer value
▶ Even an instruction like n++ is not guaranteed to be atomic on all processors!
▶ Atomic operations definitions
▶ #include <asm/atomic.h>
▶ atomic_t
▶ Contains a signed integer (at least 24 bits)
▶ Atomic operations (main ones)
▶ Set or read the counter:
▶ void atomic_set(atomic_t *v, int i);
▶ int atomic_read(atomic_t *v);
▶ Operations without return value:
▶ void atomic_inc(atomic_t *v);
▶ void atomic_dec(atomic_t *v);
▶ void atomic_add(int i, atomic_t *v);
▶ void atomic_sub(int i, atomic_t *v);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 354/470
Atomic variables 2/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 355/470
Atomic bit operations
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 357/470
Practical lab - Locking
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 358/470
Kernel debugging
Kernel debugging
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 359/470
Debugging using messages (1)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 360/470
Debugging using messages (2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 361/470
pr_debug() and dev_dbg()
▶ When the driver is compiled with DEBUG defined, all these messages are compiled
and printed at the debug level. DEBUG can be defined by #define DEBUG at the
beginning of the driver, or using ccflags-$(CONFIG_DRIVER) += -DDEBUG in the
Makefile
▶ When the kernel is compiled with CONFIG_DYNAMIC_DEBUG, then these messages
can dynamically be enabled on a per-file, per-module or per-message basis
▶ Details in admin-guide/dynamic-debug-howto
▶ Very powerful feature to only get the debug messages you’re interested in.
▶ When neither DEBUG nor CONFIG_DYNAMIC_DEBUG are used, these messages are not
compiled in.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 362/470
Configuring the priority
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 363/470
DebugFS
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 364/470
DebugFS API
▶ Create a sub-directory for your driver:
▶ struct dentry *debugfs_create_dir(const char *name,
struct dentry *parent);
▶ Expose an integer as a file in DebugFS. Example:
▶ struct dentry *debugfs_create_u8
(const char *name, mode_t mode, struct dentry *parent,
u8 *value);
▶ u8, u16, u32, u64 for decimal representation
▶ x8, x16, x32, x64 for hexadecimal representation
▶ Expose a binary blob as a file in DebugFS:
▶ struct dentry *debugfs_create_blob(const char *name,
mode_t mode, struct dentry *parent,
struct debugfs_blob_wrapper *blob);
▶ Also possible to support writable DebugFS files or customize the output using the
more generic debugfs_create_file() function.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 365/470
Deprecated debugging mechanisms
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 366/470
Using Magic SysRq
Functionnality provided by serial drivers
▶ Allows to run multiple debug / rescue commands even when the kernel seems to
be in deep trouble
▶ On PC: press [Alt] + [Prnt Scrn] + <character> simultaneously
([SysRq] = [Alt] + [Prnt Scrn])
▶ On embedded: in the console, send a break character
(Picocom: press [Ctrl] + a followed by [Ctrl] + \ ), then press <character>
▶ Example commands:
▶ h: show available commands
▶ s: sync all mounted filesystems
▶ b: reboot the system
▶ n: makes RT processes nice-able.
▶ w: shows the kernel stack of all sleeping processes
▶ t: shows the kernel stack of all running processes
▶ You can even register your own!
▶ Detailed in admin-guide/sysrq
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 367/470
kgdb - A kernel debugger
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 368/470
Using kgdb 1/2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 369/470
Using kgdb 2/2
▶ Then also pass kgdbwait to the kernel: it makes kgdb wait for a debugger
connection.
▶ Boot your kernel, and when the console is initialized, interrupt the kernel with a
break character and then g in the serial console (see our Magic SysRq
explanations).
▶ On your workstation, start gdb as follows:
▶ arm-linux-gdb ./vmlinux
▶ (gdb) set remotebaud 115200
▶ (gdb) target remote /dev/ttyS0
▶ Once connected, you can debug a kernel the way you would debug an application
program.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 370/470
Debugging with a JTAG interface
Two types of JTAG dongles
▶ The ones offering a gdb compatible interface, over a serial port or an Ethernet
connection. gdb can directly connect to them.
▶ The ones not offering a gdb compatible interface are generally supported by
OpenOCD (Open On Chip Debugger): http://openocd.sourceforge.net/
▶ OpenOCD is the bridge between the gdb debugging language and the JTAG
interface of the target CPU.
▶ See the very complete documentation: http://openocd.org/documentation/
▶ For each board, you’ll need an OpenOCD configuration file (ask your supplier)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 371/470
More kernel debugging tips
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 372/470
Practical lab - Kernel debugging
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 373/470
Porting the Linux kernel to an ARM board
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 374/470
Porting the Linux kernel
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 375/470
Architecture, CPU and Machine
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 376/470
Before the Device Tree and ARM cleanup
▶ Until 2011, the ARM architecture wasn’t using the Device Tree, and a large
portion of the SoC support was located in arch/arm/mach-<soc>.
▶ Each board supported by the kernel was associated to an unique machine ID.
▶ The entire list of machine ID can be downloaded at
https://www.arm.linux.org.uk/developer/machines/download.php and one
could freely register an additional one.
▶ The Linux kernel was defining a machine structure for each board, which
associates the machine ID with a set of information and callbacks.
▶ The bootloader had to pass the machine ID to the kernel in a specific ARM
register.
This way, the kernel knew what board it was booting on, and which init callbacks it
had to execute.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 377/470
The Device Tree and the ARM cleanup
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 378/470
Adding the support for a new ARM board
Provided the SoC used on your board is supported by the Linux kernel:
1. Create a Device Tree file in arch/arm/boot/dts/, generally named
<soc-name>-<board-name>.dts, and make it include the relevant SoC .dtsi
file.
▶ Your Device Tree will describe all the SoC peripherals that are enabled, the pin
muxing, as well as all the devices on the board.
2. Modify arch/arm/boot/dts/Makefile to make sure your Device Tree gets built
as a DTB during the kernel build.
3. Tweak an existing configuration that matches your SoC and save it as
<board-name>_defconfig in arch/arm/configs/
4. If needed, develop the missing device drivers for the devices that are on your
board outside the SoC.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 379/470
Studying the Crystalfontz CFA-10036 platform
After using a platform based on the AM335x processor from Texas Instruments, let’s
study another platform Bootlin has worked on specifically.
▶ Crystalfontz CFA-10036
▶ Uses the Freescale iMX28 SoC, from the MXS family.
▶ 128MB of RAM
▶ 1 serial port, 1 LED
▶ 1 I2C bus, equipped with an OLED display
▶ 1 SD-Card slot
Disclaimer: while the way of describing a board has slightly evolved over the past
years, the official Crystalfontz support has not. As our incentive is to show up-to-date
code and share best practices, the next snippets of code may diverge a little compared
to the upstream files.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 380/470
Crystalfontz CFA-10036 Device Tree, header
/dts-v1/;
▶ Include the .dtsi file describing the SoC
#include "imx28.dtsi"
▶ Start the root of the tree (named /) then describe the board
▶ A human-readable string to describe the machine (shown at boot time)
▶ The CFA-10036 has one debug UART. It is described in the iMX28 DTSI file, so
the corresponding controller should be referenced in the board DTS and enabled:
&duart {
pinctrl-names = "default";
pinctrl-0 = <&duart_pins_b>;
status = "okay";
};
▶ It also features an USB port which is described in the SoC DTSI but needs to be
enabled:
&usb0 {
pinctrl-names = "default";
pinctrl-0 = <&usb0_otg_cfa10036>;
status = "okay";
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 383/470
Crystalfontz CFA-10036 Device Tree, fully describe additional devices
▶ The I2C bus with a Solomon SSD1306 OLED display connected on it must be
described entirely at the location where it belongs:
apbc@80040000 {
i2c0: i2c@18000 { /* This means physical offset 0x80058000 */
reg = <0x18000 0x1000>;
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_b>;
status = "okay";
clock-frequency = <400000>;
ssd1306: oled@3c {
compatible = "solomon,ssd1306fb-i2c";
pinctrl-names = "default";
pinctrl-0 = <&ssd1306_cfa10036>;
reg = <0x3c>;
reset-gpios = <&gpio2 7 0>;
solomon,height = <32>;
solomon,width = <128>;
solomon,page-offset = <0>;
};
};
▶ Mind the display’s pin configuration that has not yet been described
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 384/470
Crystalfontz CFA-10036 Device Tree, LEDs
/ {
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&led_pins_cfa10036>;
power {
gpios = <&gpio3 4 1>;
default-state = "on";
};
};
▶ Also mind the pin configuration that we can define at any place
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 385/470
Crystalfontz CFA-10036 Device Tree, muxing
▶ Definition of a few pins that will be muxed as GPIO, for LEDs and reset.
&pinctrl {
ssd1306_cfa10036: ssd1306-10036@0 {
reg = <0>;
fsl,pinmux-ids = <0x2073>; /* MX28_PAD_SSP0_D7__GPIO_2_7 */
fsl,drive-strength = <0>;
fsl,voltage = <1>;
fsl,pull-up = <0>;
};
led_pins_cfa10036: leds-10036@0 {
reg = <0>;
fsl,pinmux-ids = <0x3043>; /* MX28_PAD_AUART1_RX__GPIO_3_4 */
fsl,drive-strength = <0>;
fsl,voltage = <1>;
fsl,pull-up = <0>;
};
};
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 386/470
Crystalfontz CFA-10036 Device Tree, Breakout Boards
▶ The CFA-10036 can be plugged in other breakout boards, and the device tree also
allows us to describe this, using includes. For example, the CFA-10057:
#include "imx28-cfa10036.dts"
▶ This allows to have a layered description. This can also be done for boards that
have a lot in common, like the BeagleBone and the BeagleBone Black, or the
AT91 SAMA5D3-based boards.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 387/470
Crystalfontz CFA-10036: build the DTB
▶ To ensure that the Device Tree Blob gets built for this board Device Tree Source,
one need to ensure it is listed in arch/arm/boot/dts/Makefile:
dtb-$(CONFIG_ARCH_MXS) +=
imx28-cfa10036.dtb \
imx28-cfa10037.dtb \
imx28-cfa10049.dtb \
imx28-cfa10055.dtb \
imx28-cfa10056.dtb \
imx28-cfa10057.dtb \
imx28-cfa10058.dtb \
imx28-evk.dtb
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 388/470
Understanding the SoC support
▶ Let’s consider another ARM platform here for the kernel side of the support: the
Marvell Armada 370/XP.
▶ For this platform, the core of the SoC support is located in
arch/arm/mach-mvebu/
▶ The board-v7.c file (see code on the next slide) contains the ”entry point” of the
SoC definition, the DT_MACHINE_START .. MACHINE_END definition:
▶ Defines the list of platform compatible strings that will match this platform, in this
case marvell,armada-370-xp. This allows the kernel to know which DT_MACHINE
structure to use depending on the DTB that is passed at boot time.
▶ Defines various callbacks for the platform initialization, the most important one being
the .init_machine callback, running initialization code for the associated SoC.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 389/470
arch/arm/mach-mvebu/board-v7.c (Linux 5.3)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 390/470
Components of the minimal SoC support
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 391/470
Extending the minimal SoC support
Once the minimal SoC support is in place, the following core components should be
added:
▶ Support for the clocks. Usually requires some clock drivers, as well as DT
representations of the clocks. See drivers/clk/mvebu/ for Armada 370/XP
clock drivers.
▶ Support for pin muxing, through the pinctrl subsystem. See
drivers/pinctrl/mvebu/ for the Armada 370/XP drivers.
▶ Support for GPIOs, through the GPIO subsystem. See
drivers/gpio/gpio-mvebu.c for the Armada 370/XP GPIO driver.
▶ Support for SMP, through struct smp_operations. See
arch/arm/mach-mvebu/platsmp.c.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 392/470
Adding controller drivers
Once the core pieces of the SoC support have been implemented, the remaining part is
to add drivers for the different hardware blocks:
▶ Ethernet controller driver, in drivers/net/ethernet/marvell/mvneta.c
▶ SATA controller driver, in drivers/ata/sata_mv.c
▶ I2C controller driver, in drivers/i2c/busses/i2c-mv64xxx.c
▶ SPI controller driver, in drivers/spi/spi-orion.c
▶ PCIe controller driver, in drivers/pci/controller/pci-mvebu.c
▶ USB controller driver, in drivers/usb/host/ehci-orion.c
▶ etc.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 393/470
Porting the Linux kernel: further reading
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 394/470
Power Management
Power Management
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 395/470
PM building blocks
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 396/470
Clock framework (1)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 397/470
Clock framework (2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 398/470
Diagram overview of the common clock framework
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 399/470
Clock framework (3)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 400/470
Clock framework (4)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 401/470
Suspend and resume (to / from RAM)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 402/470
Triggering suspend / hibernate
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 403/470
Saving power in the idle loop
▶ The idle loop is what you run when there’s nothing left to run in the system.
▶ arch_cpu_idle() implemented in all architectures in
arch/<arch>/kernel/process.c
▶ Example: arch/arm/kernel/process.c
▶ The CPU can run power saving HLT instructions, enter NAP mode, and even
disable the timers (tickless systems).
▶ See also https://en.wikipedia.org/wiki/Idle_loop
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 404/470
Managing idle
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 405/470
PowerTOP
https://01.org/powertop/
▶ With dynamic ticks, allows to fix parts of kernel code and applications that wake
up the system too often.
▶ PowerTOP allows to track the worst offenders
▶ Now available on ARM cpus implementing CPUidle
▶ Also gives you useful hints for reducing power.
▶ Try it on your x86 laptop:
sudo powertop
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 406/470
Runtime power management
▶ Managing per-device idle, each device being managed by its device driver
independently from others.
▶ According to the kernel configuration interface: Enable functionality allowing I/O
devices to be put into energy-saving (low power) states at run time (or
autosuspended) after a specified period of inactivity and woken up in response to
a hardware-generated wake-up event or a driver’s request.
▶ New hooks must be added to the drivers: runtime_suspend(),
runtime_resume(), runtime_idle() in the struct dev_pm_ops structure in
struct device_driver.
▶ API and details on power/runtime_pm
▶ See drivers/net/ethernet/cadence/macb_main.c again.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 407/470
Generic PM Domains (genpd)
Frequency and voltage scaling possible through the cpufreq kernel infrastructure.
▶ Generic infrastructure: drivers/cpufreq/cpufreq.c and
include/linux/cpufreq.h
▶ Generic governors, responsible for deciding frequency and voltage transitions
▶ performance: maximum frequency
▶ powersave: minimum frequency
▶ ondemand: measures CPU consumption to adjust frequency
▶ conservative: often better than ondemand. Only increases frequency gradually
when the CPU gets loaded.
▶ userspace: leaves the decision to a user space daemon.
▶ This infrastructure can be controlled from
/sys/devices/system/cpu/cpu<n>/cpufreq/
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 409/470
Frequency and voltage scaling (2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 410/470
Regulator framework
▶ Modern embedded platforms have hardware responsible for voltage and current
regulation
▶ The regulator framework allows to take advantage of this hardware to save power
when parts of the system are unused
▶ A consumer interface for device drivers (i.e. users)
▶ Regulator driver interface for regulator drivers
▶ Machine interface for board configuration
▶ sysfs interface for user space
▶ See power/regulator/ in kernel documentation.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 411/470
BSP work for a new board
In case you just need to create a BSP for your board, and your CPU already has full
PM support, you should just need to:
▶ Create clock definitions and bind your devices to them.
▶ Implement PM handlers (suspend, resume) in the drivers for your board specific
devices.
▶ Implement runtime PM handlers in your drivers.
▶ Implement board specific power management if needed (mainly battery
management)
▶ Implement regulator framework hooks for your board if needed.
▶ Attach on-board devices to PM domains if needed
▶ All other parts of the PM infrastructure should be already there: suspend /
resume, cpuidle, cpu frequency and voltage scaling, PM domains.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 412/470
Useful resources
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 413/470
The kernel development and contribution process
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 414/470
The kernel development and contribution process
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 415/470
Linux versioning scheme
▶ Until 2003, there was a new “stable” release branch of Linux every 2 or 3 years
(2.0, 2.2, 2.4). Development branches took 2-3 years to be merged (too slow!).
▶ Since 2003, there is a new official release of Linux about every 10 weeks:
▶ Versions 2.6 (Dec. 2003) to 2.6.39 (May 2011)
▶ Versions 3.0 (Jul. 2011) to 3.19 (Feb. 2015)
▶ Versions 4.0 (Apr. 2015) to 4.20 (Dec. 2018)
▶ Version 5.0 was released in Mar. 2019.
▶ Features are added to the kernel in a progressive way. Since 2003, kernel
developers have managed to do so without having to introduce a massively
incompatible development branch.
▶ For each release, there are bugfix and security updates called stable releases:
5.0.1, 5.0.2, etc.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 416/470
Linux development model
Using merge and bug fixing windows
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 417/470
Need for long term support (1)
▶ Issue: bug and security fixes only released for most recent kernel versions.
▶ Solution: the last release of each year is made an LTS (Long Term Support)
release, and is supposed to be supported (and receive bug and security fixes) for
up to 6 years.
▶ Example at Google: starting from Android O (2017), all new Android devices will
have to run such an LTS kernel.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 418/470
Need for long term support (2)
▶ You could also get long term support from a commercial embedded Linux
provider.
▶ Wind River Linux can be supported for up to 15 years.
▶ Ubuntu Core can be supported for up to 10 years.
▶ ”If you are not using a supported distribution kernel, or a stable / longterm kernel,
you have an insecure kernel” - Greg KH, 2019
Some vulnerabilities are fixed in stable without ever getting a CVE.
▶ The Civil Infrastructure Platform project is an industry / Linux Foundation effort
to support selected LTS versions (starting with 4.4) much longer (> 10 years).
See https://bit.ly/2hy1QYC.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 419/470
What’s new in each Linux release? (1)
The official list of changes for each Linux release is just a huge list of individual
patches!
commit aa6e52a35d388e730f4df0ec2ec48294590cc459
Author: Thomas Petazzoni <[email protected]>
Date: Wed Jul 13 11:29:17 2011 +0200
Very difficult to find out the key changes and to get the global picture out of individual
changes.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 420/470
What’s new in each Linux release? (2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 421/470
The kernel development and contribution process
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 422/470
Getting help and reporting bugs
▶ If you are using a custom kernel from a hardware vendor, contact that company.
The community will have less interest supporting a custom kernel.
▶ Otherwise, or if this doesn’t work, try to reproduce the issue on the latest version
of the kernel.
▶ Make sure you investigate the issue as much as you can: see
admin-guide/bug-bisect
▶ Check for previous bugs reports. Use web search engines, accessing public mailing
list archives.
▶ If you’re the first to face the issue, it’s very useful for others to report it, even if
you cannot investigate it further.
▶ If the subsystem you report a bug on has a mailing list, use it. Otherwise, contact
the official maintainer (see the MAINTAINERS file). Always give as many useful
details as possible.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 423/470
How to Become a Kernel Developer?
Recommended resources
▶ See process/submitting-patches for guidelines and
https://kernelnewbies.org/UpstreamMerge for very helpful advice to have
your changes merged upstream (by Rik van Riel).
▶ Watch the Write and Submit your first Linux kernel Patch talk by Greg. K.H:
https://www.youtube.com/watch?v=LLBrBBImJt4
▶ How to Participate in the Linux Community (by Jonathan Corbet). A guide to the
kernel development process https://j.mp/tX2Ld6
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 424/470
Contribute to the Linux Kernel (1)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 425/470
Contribute to the Linux Kernel (2)
▶ Either create a new branch starting from the current commit in the master
branch:
▶ git checkout -b feature
▶ Or, if more appropriate, create a new branch starting from the maintainer’s
master branch:
▶ git checkout -b feature linux-omap/master (remote tree / remote branch)
▶ In your new branch, implement your changes.
▶ Test your changes (must at least compile them).
▶ Run git add to add any new files to the index.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 426/470
Configure git send-email
▶ Make sure you already have configured your name and e-mail address (should be
done before the first commit).
▶ git config --global user.name 'My Name'
▶ git config --global user.email [email protected]
▶ Configure your SMTP settings. Example for a Google Mail account:
▶ git config --global sendemail.smtpserver smtp.googlemail.com
▶ git config --global sendemail.smtpserverport 587
▶ git config --global sendemail.smtpencryption tls
▶ git config --global sendemail.smtpuser [email protected]
▶ git config --global sendemail.smtppass xxx
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 427/470
Contribute to the Linux Kernel (3)
▶ Group your changes by sets of logical changes, corresponding to the set of patches
that you wish to submit.
▶ Commit and sign these groups of changes (signing required by Linux developers).
▶ git commit -s
▶ Make sure your first description line is a useful summary and starts with the name of
the modified subsystem. This first description line will appear in your e-mails
▶ The easiest way is to look at previous commit summaries on the main file you
modify
▶ git log --pretty=oneline <path-to-file>
▶ Examples subject lines ([PATCH] omitted):
Documentation: prctl/seccomp_filter
PCI: release busn when removing bus
ARM: add support for xz kernel decompression
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 428/470
Contribute to the Linux Kernel (4)
▶ Remove previously generated patches
▶ rm 00*.patch
▶ Have git generate patches corresponding to your branch (assuming it is the
current branch)
▶ If your branch is based on mainline
▶ git format-patch master
▶ If your branch is based on a remote branch
▶ git format-patch <remote>/<branch>
▶ Make sure your patches pass checkpatch.pl checks:
▶ scripts/checkpatch.pl --strict 00*.patch
▶ Now, send your patches to yourself
▶ git send-email --compose --to [email protected] 00*.patch
▶ If you have just one patch, or a trivial patch, you can remove the empty line after
In-Reply-To:. This way, you won’t add a summary e-mail introducing your
changes (recommended otherwise).
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 429/470
Contribute to the Linux Kernel (5)
▶ Check that you received your e-mail properly, and that it looks good.
▶ Now, find the maintainers for your patches
scripts/get_maintainer.pl ~/patches/00*.patch
Russell King <[email protected]> (maintainer:ARM PORT)
Nicolas Pitre <[email protected]>
(commit_signer:1/1=100%)
[email protected] (open list:ARM PORT)
[email protected] (open list)
▶ Now, send your patches to each of these people and lists
▶ git send-email --compose --to [email protected] --
to [email protected] --cc linux-arm-
[email protected] --cc [email protected] 00*.patch
▶ Wait for replies about your changes, take the comments into account, and
resubmit if needed, until your changes are eventually accepted.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 430/470
Contribute to the Linux Kernel (6)
▶ If you use git format-patch to produce your patches, you will need to update
your branch and may need to group your changes in a different way (one patch
per commit).
▶ Here’s what we recommend
▶ Update your master branch
▶ git checkout master; git pull
▶ Back to your branch, implement the changes taking community feedback into
account. Commit these changes.
▶ Still in your branch: reorganize your commits and commit messages
▶ git rebase --interactive origin/master
▶ git rebase allows to rebase (replay) your changes starting from the latest commits in
master. In interactive mode, it also allows you to merge, edit and even reorder
commits, in an interactive way.
▶ Third, generate the new patches with git format-patch.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 431/470
Kernel Resources
Kernel Resources
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 432/470
Kernel Development News
▶ https://lwn.net/
▶ The weekly digest off all Linux and free software
information sources
▶ In depth technical discussions about the kernel
▶ Subscribe to finance the editors ($7 / month)
▶ Articles available for non subscribers after 1 week.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 433/470
Useful Reading (1)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 434/470
Useful Reading (2)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 435/470
Useful Online Resources
▶ Kernel documentation
▶ https://kernel.org/doc/
▶ Linux kernel mailing list FAQ
▶ http://vger.kernel.org/lkml/
▶ Complete Linux kernel FAQ
▶ Read this before asking a question to the mailing list
▶ Kernel Newbies
▶ https://kernelnewbies.org/
▶ Glossary, articles, presentations, HOWTOs, recommended reading, useful tools for
people getting familiar with Linux kernel or driver development.
▶ Kernel glossary
▶ https://kernelnewbies.org/KernelGlossary
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 436/470
International Conferences (1)
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 438/470
Continue to learn after the course
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 439/470
Last slides
Last slides
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 440/470
Last slide
Thank you!
And may the Source be with you
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 441/470
Backup slides
Backup slides
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 442/470
Backup slides
DMA
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 443/470
DMA integration
DMA (Direct Memory Access) is used to copy data directly between devices and RAM,
without going through the CPU.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 444/470
Peripheral DMA
Some device controllers embedded their own DMA controller and therefore can do
DMA on their own.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 445/470
DMA controllers
Other device controllers rely on an external DMA controller (on the SoC). Their drivers
need to submit DMA descriptors to this controller.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 446/470
DMA descriptors
DMA descriptors describe the various attributes of a DMA transfer, and are chained.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 447/470
Backup slides
DMA usage
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 448/470
Constraints with a DMA
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 449/470
DMA memory constraints
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 450/470
Memory synchronization issues
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 451/470
Linux DMA API
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 452/470
Coherent or streaming DMA mappings
▶ Coherent mappings
▶ The kernel allocates a suitable buffer and sets the mapping for the driver.
▶ Can simultaneously be accessed by the CPU and device.
▶ So, has to be in a cache coherent memory area.
▶ Usually allocated for the whole time the module is loaded.
▶ Can be expensive to setup and use on some platforms.
▶ Streaming mappings
▶ The kernel just sets the mapping for a buffer provided by the driver.
▶ Use an already allocated buffer
▶ Mapping set up for each transfer. Keeps DMA registers free on the hardware.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 453/470
Allocating coherent mappings
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 454/470
Setting up streaming mappings
dma_addr_t dma_map_single(
struct device *, /* device structure */
void *, /* input: buffer to use */
size_t, /* buffer size */
enum dma_data_direction /* Either DMA_BIDIRECTIONAL,
* DMA_TO_DEVICE or
* DMA_FROM_DEVICE */
);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 455/470
DMA notes
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 456/470
Backup slides
DMA transfers
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 457/470
Starting DMA transfers
▶ If the device you’re writing a driver for is doing peripheral DMA, no external API
is involved.
▶ If it relies on an external DMA controller, you’ll need to
▶ Ask the hardware to use DMA, so that it will drive its request line
▶ Use Linux DMAEngine framework, especially its slave API
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 458/470
DMAEngine slave API 1/2
In order to start a DMA transfer with DMAEngine, you need to call the following
functions from your driver
1. Request a channel for exclusive use with dma_request_channel(), or one of its
variants
2. Configure it for our use case, by filling a struct dma_slave_config structure
with various parameters (source and destination adresses, accesses width, etc.)
and passing it as an argument to dmaengine_slave_config()
3. Start a new transaction with dmaengine_prep_slave_single() or
dmaengine_prep_slave_sg()
4. Put the transaction in the driver pending queue using dmaengine_submit()
5. And finally ask the driver to process all pending transactions using
dma_async_issue_pending()
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 459/470
DMAEngine slave API 2/2
▶ Of course, all this needs to be done in addition to the DMA mapping seen
previously
▶ Some frameworks abstract it away, such as SPI and ASoC
▶ Example usage of the slave API: look at the code for
stm32_i2c_prep_dma_xfer().
Details in kernel documentation: driver-api/dmaengine/client
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 460/470
Backup slides
mmap
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 461/470
mmap
▶ Possibility to have parts of the virtual address space of a program mapped to the
contents of a file
▶ Particularly useful when the file is a device file
▶ Allows to access device I/O memory and ports without having to go through
(expensive) read, write or ioctl calls
▶ One can access to current mapped files by two means:
▶ /proc/<pid>/maps
▶ pmap <pid>
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 462/470
/proc/<pid>/maps
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 463/470
mmap overview
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 464/470
How to Implement mmap - User space
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 465/470
How to Implement mmap - Kernel space
▶ Character driver: implement an mmap file operation and add it to the driver file
operations:
int (*mmap) (
struct file *, /* Open file structure */
struct vm_area_struct * /* Kernel VMA structure */
);
▶ Initialize the mapping.
▶ Can be done in most cases with the remap_pfn_range() function, which takes care
of most of the job.
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 466/470
remap_pfn_range()
int remap_pfn_range(
struct vm_area_struct *, /* VMA struct */
unsigned long virt_addr, /* Starting user
* virtual address */
unsigned long pfn, /* pfn of the starting
* physical address */
unsigned long size, /* Mapping size */
pgprot_t prot /* Page permissions */
);
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 467/470
Simple mmap implementation
static int acme_mmap
(struct file * file, struct vm_area_struct *vma)
{
size = vma->vm_end - vma->vm_start;
if (remap_pfn_range(vma,
vma->vm_start,
ACME_PHYS >> PAGE_SHIFT,
size,
vma->vm_page_prot))
return -EAGAIN;
return 0;
}
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 468/470
devmem2
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 469/470
mmap summary
- Kernel, drivers and embedded Linux - Development, consulting, training and support - https://bootlin.com 470/470