Reducing the Size of the Kernel - Linux Embedded systems

The kernel isn’t that much different from a regular executable file. The first step to reducing its size is finding code that will never be executed and remove it. However, unlike regular programs, the kernel comes equipped with a great tool for picking and choosing code that goes into the build: the configuration editor. The kernel’s configuration editor lets you remove large chunks of code by quickly and easily disabling features or removing support for hardware that isn’t in the project. This work is divided into two basic parts: removing drivers that aren’t used, and removing kernel features. Let’s look at drivers first, because that’s where you can get the greatest reduction very quickly.

Removing Unneeded Features and Drivers

There isn’t a magic way for you to know what to remove in terms of drivers; it’s a matter of removing from the kernel drivers that support hardware that isn’t on your target board. The best approach is to make a list of the hardware on the device and then remove support for peripherals that aren’t present.

Because most embedded devices have a fixed inventory of devices, you can safely remove the drivers for components that aren’t on the board or will never be used, because that code will never be run.

The question is: what can be removed? The kernel has no “make this smaller” utility; instead, you must understand what your system needs in terms of drivers and functionality and then remove what’s unneeded. The configuration files for the kernel keep track of what components rely on the one selected, so if the component you want to remove is required by something else, you can’t remove it until its dependencies are removed.

Here are some general guidelines to help you figure out what to remove from the kernel:

  • File systems: Your system will only use a few file systems, but the kernel build you have probably includes several unused file system drivers. For example, a device that uses a flash file system likely doesn’t need the ext2 or ext3 file system (it may if the device has a USB interface or some other interface for external storage; the point is that you need to understand your application before removing things from the kernel), and these are often included in the kernel by default. Any file system that’s not being used now or in the future can be removed. The NFS file system is a particularly large item, taking several hundred KB of memory and about twice that during runtime. A convenience while debugging, the NFS file system on a device not connected to the network is a waste of resources.
  • Hardware drivers: Hardware that won’t be used shouldn’t have a corresponding driver built into the kernel. Many systems-on-chip (SOCs) have Wi-Fi drivers, video, serial, and other hardware interfaces that will never be used and therefore have no need for a driver. In fact, drivers for unused hardware leave a security risk open on the device.
  • Input and output: Although this seems like the hardware drivers already mentioned, it’s a little different in that the kernel has special drivers for using the mouse and VGA console. On devices that contain a serial port or use a graphics driver on the frame buffer, a console on the same device as the UI wastes memory and resources. Likewise, keyboard support for a device with only a touchscreen is also wasted memory.
  • Debugging and profiling: Under the Kernel Hacking entry on the main menu are many options designed for those doing kernel debugging. In a production system, all options under this menu entry can be disabled.
  • Networking: A device without networking hardware that doesn't also use networking for interprocess communication, so you can remove the networking stack. The networking stack contributes about 200KB to the Linux kernel. Before removing this feature, check that the programs aren’t using TCP connections to localhost or as a way to communicate between processes. Using TCP as a way to transport data between processes is common, even if the device doesn’t have a physical network adapter, because the localhost device is a logical network adapter that doesn’t have a physical termination point.

Recommendations for Embedded Systems

The kernel configuration program now has a menu that aggregates the most common items embedded engineers change when configuring the kernel. Go to the General Setup menu , and look for “Configure standard kernel features (for small systems).” Enabling this option results in the following items becoming visible under this menu:

  • Enable 16-bit UID system calls: This is for compatibility with older programs that used system calls where the UID was a single byte. Generally, these programs were created when the 2.4 kernel was current; it used an older glibc version. Because you control what is running on the OS and you’re likely using newer software, this compatibility option can be disabled, saving a marginal amount of memory.
  • Sysctl syscall support: When the sys file system was first introduced, early in the 2.6 release cycle, some of the paths used numbers and not strings to represent their corresponding kernel object. The string method of accessing data in the sys file system is now the default; unless you know you’re using the older style, this can be dropped to save a few kilobytes.
  • Load all symbols for debugging/ksymoops: When the kernel dies due to panic, the output contains the names of the functions in the call stack before the crash.
    Unselecting this item removes the symbolic information from the crash dumps. If your embedded system doesn’t have a good way to view crash-dump information, the extra data this produces is wasted. Unselecting this option yields a substantial drop in size—over 200KB—because this information is the text for all of the kernel’s function call names.
  • Support for hot-pluggable devices: This code supports the dynamic assignment of USB device nodes when a new hardware device appears on the USB wire. If your device doesn’t have USB, this code isn’t necessary; if your device does have USB and you’re supporting a known subset of items, and therefore have created the /dev entries for the devices, you can also disable this feature.
  • Enable support for printk: Printk is the kernel equivalent of printf. Many drivers and kernel modules use it as a way of reporting the state, errors, and other information. This is the data that eventually makes its way into /var/log/messages. Disabling this results in printk turning into a macro that basically does nothing. This is a great way to reduce the size of the kernel, but at the expense of losing valuable diagnostic data that makes diagnosing problems much easier. However, if your device has no user interface but an LED or two and no way to store printk data, removing printk is a perfectly sensible thing to do. If you’re working with a device that has some storage and a way to access it, consider disabling this only for the final production build.
  • BUG() support: The BUG() macro is the kernel equivalent to assert. For most embedded systems, this can be removed, because the opportunity to act on this information is limited.
  • Enable ELF core dumps: When a process dies, it can produce a dump of its memory state, or what’s called a core dump. If your system doesn’t have the room to store this file or you can’t easily get it from the device, disabling this item saves a few kilobytes.
  • Enable full-sized data structures for core: Unselecting this item reduces memory usage at runtime by reducing in the kernel various data structures and buffers, including the number of lines kept in the console rollback buffer and the maximum process ID (PID). These reductions help control the amount of RAM Linux needs while running.
  • Enable futex support: Removing this option drops support for Fast User Space Mutexes. These are the building blocks for much of the POSIX interthread communication. Although this saves a few KB, most applications depend on this code being present, so removing it isn’t recommended.
  • Enable eventpoll support: The event-poll set of functions provide a superset of poll() functions. Most programs don’t use this functionality, and it can be dropped from the kernel.
  • Enable signalfd() system call: This system call allows you to create a file descriptor that receives signals sent to the program, instead of registering a signal handler. You should leave this enabled unless you know it isn’t used on your system, because this new feature is quickly becoming a common way for a program to handle signals.
  • Enable timerfd() system call: Like the signalfd, this is functionality that wraps timer events in file-based semantics. It doesn’t require much space and should be left enabled.
  • Enable eventfd() system call: An eventfd is a low-resource notification system that works something like a semaphore. It’s an IPC call that notifies another process that an event has occurred; it can be used to replace a pipe that passes one character (or other token) to notify the listening process of a state change.
    This is a very low resource feature that you should leave enabled unless you know for certain it isn’t being used.
  • Use full shmem filesystem: Disabling this code replaces the internal file system used to manage memory resources with a much less complex RAM-based solution. If you have an embedded systems without swap memory, unselect this item and enjoy the extra few kilobytes of memory.
  • Enable AIO support: Asynchronous I/O (AIO) means input/output requests are scheduled by the kernel, and the caller doesn’t wait for an I/O operation to complete before it gets control back. Having control over I/O is helpful for embedded systems, because the kernel has fewer places where the system can become blocked waiting for an IO device; otherwise, it can be disabled.

All rights reserved © 2020 Wisdom IT Services India Pvt. Ltd Protection Status

Linux Embedded systems Topics