Section 4.2. Linux Kernel Construction


4.2. Linux Kernel Construction

In the next few sections, we explore the layout, organization, and construction of the Linux kernel. Armed with this knowledge, you will find it much easier to navigate this large, complex source code base. Over time, there have been significant improvements in the organization of the source tree, especially in the architecture branch, which contains support for numerous architectures and specific machines. As this book is being written, an effort is underway to collapse the ppc and ppc64 architecture branches into a single common powerpc branch. When the dust settles, there will be many improvements, including elimination of duplicate code, better organization of files, and partitioning of functionality.

4.2.1. Top-Level Source Directory

We make frequent reference to the top-level source directory throughout the book. In every case, we are referring to the highest-level directory contained in the kernel source tree. On any given machine, it might be located anywhere, but on a desktop Linux workstation, it is often found in /usr/src/linux-x.y.z, where x.y.z represents the kernel version. Throughout the book, we use the shorthand .../ to represent the top-level kernel source directory.

The top-level kernel source directory contains the following subdirectories. (We have omitted the nondirectory entries in this listing, as well as directories used for source control for clarity and brevity.)

arch    crypto   Documentation   drivers fs     include init    ipc      kernel  lib     mm      net scripts security sound   usr


Many of these subdirectories contain several additional levels of subdirectories containing source code, makefiles, and configuration files. By far the largest branch of the Linux kernel source tree is found under .../drivers. Here you can find support for Ethernet network cards, USB controllers, and the numerous hardware devices that the Linux kernel supports. As you might imagine, the .../arch subdirectory is the next largest, containing support for more than 20 unique processor architectures.

Additional files found in the top-level Linux subdirectory include the top-level makefile, a hidden configuration file (dot-config, introduced in Section 4.3.1, "The Dot-Config") and various other informational files not involved in the build itself. Finally, two important build targets are found in the top-level kernel source tree after a successful build: System.map and the kernel proper, vmlinux. Both are described shortly.

4.2.2. Compiling the Kernel

Understanding a large body of software such as Linux can be a daunting task. It is too large to simply "step through" the code to follow what is happening. Multithreading and preemption add to the complexity of analysis. In fact, even locating the entry point (the first line of code to be executed upon entry to the kernel) can be challenging. One of the more useful ways to understand the structure of a large binary image is to examine its built components.

The output of the kernel build system produces several common files, as well as one or more architecture-specific binary modules. Common files are always built regardless of the architecture. Two of the common files are System.map and vmlinux, introduced earlier. The former is useful during kernel debug and is particularly interesting. It contains a human-readable list of the kernel symbols and their respective addresses. The latter is an architecture-specific ELF[3] file in executable format. It is produced by the top-level kernel makefile for every architecture. If the kernel was compiled with symbolic debug information, it will be contained in the vmlinux image. In practice, although it is an ELF executable, this file is usually never booted directly, as you will see shortly.

[3] Executable and Linking Format, a de-facto standard format for binary executable files.

Listing 4-2 is a snippet of output resulting from executing make in a recent kernel tree configured for the ARM XScale architecture. The kernel source tree was configured for the ADI Engineering Coyote reference board based on the Intel IXP425 network processor using the following command:

make ARCH=arm CROSS_COMPILE=xscale_be- ixp4xx_defconfig


This command does not build the kernel; it prepares the kernel source tree for the XScale architecture including an initial default configuration for this architecture and processor. It builds a default configuration (the dot-config file) that drives the kernel build, based on the defaults found in the ixp4xx_defconfig file. We have more to say about the configuration process later, in Section 4.3, "Kernel Build System."

Listing 4-2 shows the command that builds the kernel. Only the first few and last few lines of the build output are shown for this discussion.

Listing 4-2. Kernel Build Output

$ make ARCH=arm CROSS_COMPILE=xscale_be- zImage       CHK      include/linux/version.h       HOSTCC   scripts/basic/fixdep       .       . <hundreds of lines of output omitted here>       .       LD       vmlinux       SYSMAP   System.map       SYSMAP   .tmp_System.map       OBJCOPY  arch/arm/boot/Image       Kernel:  arch/arm/boot/Image is ready       AS       arch/arm/boot/compressed/head.o       GZIP     arch/arm/boot/compressed/piggy.gz       AS       arch/arm/boot/compressed/piggy.o       CC       arch/arm/boot/compressed/misc.o       AS       arch/arm/boot/compressed/head-xscale.o       AS       arch/arm/boot/compressed/big-endian.o       LD       arch/arm/boot/compressed/vmlinux       OBJCOPY  arch/arm/boot/zImage       Kernel:  arch/arm/boot/zImage is ready       Building modules, stage 2.       ...

To begin, notice the invocation of the build. Both the desired architecture (ARCH=arm) and the toolchain (CROSS_COMPILE=xscale_be-) were specified on the command line. This forces make to use the XScale toolchain to build the kernel image and to use the arm-specific branch of the kernel source tree for architecture-dependent portions of the build. We also specify a target called zImage. This target is common to many architectures and is described in Chapter 5, "Kernel Initialization."

The next thing you might notice is that the actual commands used for each step have been hidden and replaced with a shorthand notation. The motivation behind this was to clean up the build output to draw more attention to intermediate build issues, particularly compiler warnings. In earlier kernel source trees, each compilation or link command was output to the console verbosely, which often required several lines for each step. The end result was virtually unreadable, and compiler warnings slipped by unnoticed in the noise. The new system is definitely an improvement because any anomaly in the build process is easily spotted. If you want or need to see the complete build step, you can force verbose output by defining V=1 on the make command line.

We have omitted most of the actual compilation and link steps in Listing 4-2, for clarity. (This particular build has more than 900 individual compile and link commands in the build. That would have made for a long listing, indeed.) After all the intermediate files and library archives have been built and compiled, they are put together in one large ELF build target called vmlinux. Although it is architecture specific, this vmlinux target is a common targetit is produced for all supported Linux architectures.

4.2.3. The Kernel Proper: vmlinux

Notice this line in Listing 4-2:

LD /arch/arm/boot/compressed/vmlinux


The vmlinux file is the actual kernel proper. It is a fully stand-alone, monolithic image. No unresolved external references exist within the vmlinux binary. When caused to execute in the proper context (by a bootloader designed to boot the Linux kernel), it boots the board on which it is running, leaving a completely functional kernel.

In keeping with the philosophy that to understand a system one must first understand its parts, let's look at the construction of the vmlinux kernel object.Listing 4-3 reproduces the actual link stage of the build process that resulted in the vmlinux ELF object. We have formatted it with line breaks (indicated by the UNIX line-continuation character, '\') to make it more readable, but otherwise it is the exact output produced by the vmlinux link step in the build process from Listing 4-2. If you were building the kernel by hand, this is the link command you would issue from the command line.

Listing 4-3. Link Stage: vmlinux

xscale_be-ld -EB  -p --no-undefined -X -o vmlinux    \ -T arch/arm/kernel/vmlinux.lds                       \ arch/arm/kernel/head.o                               \ arch/arm/kernel/init_task.o                          \ init/built-in.o                                      \ --start-group                                        \ usr/built-in.o                                       \ arch/arm/kernel/built-in.o                           \ arch/arm/mm/built-in.o                               \ arch/arm/common/built-in.o                           \ arch/arm/mach-ixp4xx/built-in.o                      \ arch/arm/nwfpe/built-in.o                            \ kernel/built-in.o                                    \ mm/built-in.o                                        \ fs/built-in.o                                        \ ipc/built-in.o                                       \ security/built-in.o                                  \ crypto/built-in.o                                    \ lib/lib.a                                            \ arch/arm/lib/lib.a                                   \ lib/built-in.o                                       \ arch/arm/lib/built-in.o                              \ drivers/built-in.o                                   \ sound/built-in.o                                     \ net/built-in.o                                       \ --end-group                                          \ .tmp_kallsyms2.o

4.2.4. Kernel Image Components

From Listing 4-3, you can see that the vmlinux image consists of several composite binary images. Right now, it is not important to understand the purpose of each component. What is important is to understand the top-level view of what components make up the kernel. The first line of the link command in Listing 4-3 specifies the output file (-o vmlinux.) The second line specifies the linker script file (-T vmlinux.lds), a detailed recipe for how the kernel binary image should be linked. [4]

[4] The linker script file has a peculiar syntax. The details can be found in the documentation for the GNU linker.

The third and subsequent lines from Listing 4-3 specify the object modules that form the resulting binary image. Notice that the first object specified is head.o. This object was assembled from /arch/arm/kernel/head.S, an architecture-specific assembly language source file that performs very low-level kernel initialization. If you were searching for the first line of code to be executed by the kernel, it would make sense to start your search here because it will ultimately be the first code found in the binary image created by this link stage. We examine kernel initialization in detail in Chapter 5.

The next object, init_task.o, sets up initial thread and task structures that the kernel requires. Following this is a large collection of object modules, each having a common name: built-in.o. You will notice, however, that each built-in.o object comes from a specific part of the kernel source tree, as indicated by the path component preceding the built-in.o object name. These are the binary objects that are included in the kernel image. An illustration might make this clearer.

Figure 4-1 illustrates the binary makeup of the vmlinux image. It contains a section for each line of the link stage. It's not to scale because of space considerations, but you can see the relative sizes of each functional component.

Figure 4-1. vmlinux image components


It might come as no surprise that the three largest binary components are the file system code, the network code, and all the built-in drivers. If you take the kernel code and the architecture-specific kernel code together, this is the next-largest binary component. Here you find the scheduler, process and thread management, timer management, and other core kernel functionality. Naturally, the kernel contains some architecture-specific functionality, such as low-level context switching, hardware-level interrupt and timer processing, processor exception handling, and more. This is found in .../arch/arm/kernel.

Bear in mind that we are looking at a specific example of a kernel build. In this particular example, we are building a kernel specific to the ARM XScale architecture and, more specifically, the Intel IXP425 network processor on the ADI Engineering reference board. You can see the machine-specific binary components in Figure 4-1 as arch/arm/mach-ixp4xx. Each architecture and machine type (processor/reference board) has different elements in the architecture-specific portions of the kernel, so the makeup of the vmlinux image is slightly different. When you understand one example, you will find it easy to navigate others.

To help you understand the breakdown of functionality in the kernel source tree, Table 4-1 lists each component in Figure 4-1, together with a short description of each binary element that makes up the vmlinux image.

Table 4-1. vmlinux Image Components Description

Component

Description

arch/arm/kernel/head.o

Kernel architecture-specific startup code.

init_task.o

Initial thread and task structs required by kernel.

init/built-in.o

Main kernel-initialization code. See Chapter 5.

usr/built-in.o

Built-in initramfs image. See Chapter 5.

arch/arm/kernel/built-in.o

Architecture-specific kernel code.

arch/arm/mm/built-in.o

Architecture-specific memory-management code.

arch/arm/common/built-in.o

Architecture-specific generic code. Varies by architecture.

arch/arm/mach-ixp4xx/built-in.o

Machine-specific code, usually initialization.

arch/arm/nwfpe/built-in.o

Architecture-specific floating point-emulation code.

kernel/built-in.o

Common components of the kernel itself.

mm/built-in.o

Common components of memory-management code.

ipc/built-in.o

Interprocess communications, such as SysV IPC.

security/built-in.o

Linux security components.

lib/lib.a

Archive of miscellaneous helper functions.

arch/arm/lib/lib.a

Architecture-specific common facilities. Varies by architecture.

lib/built-in.o

Common kernel helper functions.

drivers/built-in.o

All the built-in driversnot loadable modules.

sound/built-in.o

Sound drivers.

net/built-in.o

Linux networking.

.tmp_kallsyms2.o

Symbol table.


When we speak of the kernel proper, this vmlinux image is being referenced. As mentioned earlier, very few platforms boot this image directly. For one thing, it is almost universally compressed. At a bare minimum, a bootloader must decompress the image. Many platforms require some type of stub bolted onto the image to perform the decompression. Later in Chapter 5, you will learn how this image is packaged for different architectures, machine types, and bootloaders, and the requirements for booting it.

4.2.5. Subdirectory Layout

Now that you've seen how the build system controls the kernel image, let's take a look at a representative kernel subdirectory. Listing 4-4 details the contents of the mach-ixp425 subdirectory. This directory exists under the .../arch/arm architecture-specific branch of the source tree.

Listing 4-4. Kernel Subdirectory

$ ls -l linux-2.6/arch/arm/mach-ixp425 total 92 -rw-rw-r--  1 chris   chris   11892 Oct 10 14:53 built-in.o -rw-rw-r--  1 chris   chris    6924 Sep 29 15:39 common.c -rw-rw-r--  1 chris   chris    3525 Oct 10 14:53 common.o -rw-rw-r--  1 chris   chris   13062 Sep 29 15:39 common-pci.c -rw-rw-r--  1 chris   chris    7504 Oct 10 14:53 common-pci.o -rw-rw-r--  1 chris   chris    1728 Sep 29 15:39 coyote-pci.c -rw-rw-r--  1 chris   chris    1572 Oct 10 14:53 coyote-pci.o -rw-rw-r--  1 chris   chris    2118 Sep 29 15:39 coyote-setup.c -rw-rw-r--  1 chris   chris    2180 Oct 10 14:53 coyote-setup.o -rw-rw-r--  1 chris   chris    2042 Sep 29 15:39 ixdp425-pci.c -rw-rw-r--  1 chris   chris    3656 Sep 29 15:39 ixdp425-setup.c -rw-rw-r--  1 chris   chris    2761 Sep 29 15:39 Kconfig -rw-rw-r--  1 chris   chris     259 Sep 29 15:39 Makefile -rw-rw-r--  1 chris   chris    3102 Sep 29 15:39 prpmc1100-pci.c

The directory contents in Listing 4-4 have common components found in many kernel source subdirectories: Makefile and Kconfig. These two files drive the kernel configuration-and-build process. Let's look at how that works.



Embedded Linux Primer(c) A Practical Real-World Approach
Embedded Linux Primer: A Practical Real-World Approach
ISBN: 0131679848
EAN: 2147483647
Year: 2007
Pages: 167

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net