Many fans asked in the group how to compile a module file into the kernel or mutate it into a KO file. This article gives you a detailed explanation.

1. Kernel directory

The Linux kernel source code is huge and grows with releases. It uses a directory tree structure and makefiles to organize configuration and compilation.

For your first time with the Linux kernel, read the readme file in the top directory, which provides an overview of the Linux kernel and instructions for compiling commands. Readme’s instructions focus on generic platforms such as X86, and may have special instructions for specific architectures.

The Makefile of the top-level directory is the core file of the entire kernel configuration and compilation. It is responsible for organizing the compilation and management of subdirectories in the directory tree, and can also set the architecture and version number.

The top layer of kernel source code has a number of subdirectories, organized to house various kernel subsystems or files. The following table describes specific directories.

directory content
arch/ Architecture related code, such as ARCH/I386, ARCH/ARM, ARCH/PPC
crypto Commonly used encryption and hash algorithms (such as AES, SHA, etc.), as well as some compression and CRC check algorithms
drivers/ Various device drivers, such as drivers/char, drivers/block…
documentation/ The kernel documentation
fs/ File systems such as FS /ext3 and FS/jFFs2……
include/ Kernel header file: include/ ASM is an architecture-related header file, which is a link to include/ ASM-arm, include/ ASM-i386, etc. Include/Linux is a basic header file for the Linux kernel
init/ Linux initialization, such as main.c
ipc/ Code for interprocess communication
kernel/ Linux kernel core code (this section is relatively small)
lib/ Various library subroutines, such as zlib, crC32
mm/ Memory management code
net/ Network support code, mainly network protocol
sound Sound driven support
scripts/ Scripts for internal or external use
usr/ User code

2. Compilation tools

  1. Make mrproper: clears configuration files and object files generated by the kernel, usually used during the first build

  2. Import default configuration information (in kernel root)

A) make xxx_deconfig b) cp arch/arm/configs/ xx_deconfig. config Generate the default configuration fileCopy the code
  1. Configuration commands
Make xconfig make menuconfig sudo apt-get install libncurses5-dev Make configCopy the code
  1. Compile the kernel
Make uImage /arch/arm/boot/uImageCopy the code
  1. Compiling device tree
Make DTBS - generate device tree files/the arch/arm/boot/DTB/XXXXXX DTBCopy the code
  1. Build the module file
Make modules -- Code that sets the configuration value to M is compiled to generate module files. (.ko) in the corresponding source directory.Copy the code

3. Kernel compilation

Many linux-based products are now developed with integrated development environment SDKS. Builroot makes it easier to build environments, but as a beginner we still need to learn how to compile kernel source independently.

0) Prerequisites

You must install the cross-compile tool chain first. For details on how to install the cross-compile tool chain, please refer to the Linux Environment Setup – Ubuntu16.04 Installation.

Here we use arm-none-linux-gnueabi-gcc.

1) Download the kernel source

Download address: mirrors.edge.kernel.org/pub/linux/k…

We downloaded the Linux-3.14 kernel (or later) to the /home/peng directory.

Or directly click the following link mirrors.edge.kernel.org/pub/linux/k…

Unlock the compressed package and enter the kernel source directory, the specific process is as follows:

$tar XVF linux-3.14.tar.xz $cdLinux - 3.14 -Copy the code

2) Modify the Makefile under the root of the kernel directory to specify the cross-compiler:

   $ vim Makefile
Copy the code

Find ARCH and CROSS_COMPILE, modify:

ARCH ? = $(SUBARCH) CROSS_COMPILE ? = $(CONFIG_CROSS_COMPILE:"%"= %)Copy the code

for

ARCH ? = arm CROSS_COMPILE ? = arm-none-linux-gnueabi-Copy the code

4) Config file:

Importing Default Configurations

$ make  exynos_defconfig
Copy the code

Here we assume that to compile the kernel eventually run on samsung’s board, soc name is exynos, samsung actually has its own configuration file placed in the arch/arm/configs/exynos_defconfig

This command will eventually generate a.config file in the kernel root directory,

We rely entirely on this file to compile the kernel. This file is the kernel module macro definitions and parameter Settings required by the Exynos development board. These values are an initial configuration given by the vendor. In the actual project development, you need to re-transplant the corresponding driver module you need on the basis of this configuration file.

5) Configure the kernel module

Enter the kernel configuration command to select kernel options as follows:

$ make menuconfig
Copy the code

After the command is executed successfully, the following figure is displayed. In fact, we have seen the same interface in Figure 1.5, which is also the kernel options configuration interface, except that this interface can only be executed under x-Window.

Among them:

  1. Sub menu – >

Indicates that there is a submenu. Press Enter to enter the submenu.

  1. Brackets []

Each option is preceded by parentheses, either middle parentheses, Angle parentheses, or parentheses.

[] indicates that the option has only two options. The brackets are empty or asterisks (*).

Use the space bar to make a choice.

  1. Angle brackets < >

<> When you select a configuration, there are three options, which represent the following meanings.

● * : Compile this functionality into the kernel. ● Empty: This feature is not compiled into the kernel. ● M: Compile this functionality into modules that can be dynamically inserted into the kernel as needed.Copy the code
  1. Module configuration parentheses ()

The content of the parentheses is to ask you to select one of several options provided.

If you are using make Xconfig, use the mouse to select the corresponding option. If you use Make Menuconfig, use the Enter key to select.

The troublesome part of compiling the kernel is the configuration part. Developers new to the Linux kernel often have trouble figuring out how to select these options.

In fact, most options can be configured with their default values, and only a few options need to be selected depending on the user’s needs.

The principle of selection is to compile some function codes that are far from other parts of the kernel and are not often used into loadable modules, which is conducive to reducing the length of the kernel, reducing the memory consumed by the kernel, and simplifying the influence of the corresponding environment change of this function on the kernel. Don’t select features you don’t need; Some of the functional code that is closely related to the kernel and often used is compiled directly into the kernel.

6) Compiling the kernel:

root@ubuntu:/home/peng/linux3.14# make uImage
Copy the code

If the default configuration is not changed, a uImage file will be generated in arch/ ARM /boot, which is just generated.

7) Download the Linux kernel

Because different boards have different uboot versions, the uboot commands used to download programs may also be different. Verification is not discussed in this article.

4. Compilation of independent drivers

1. Compile into independent modules

Suppose we have the following driver that we want to compile into a separate KO file that can be loaded into the development board

hello.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
//#include <io/uaccess.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>

static int major = 237;
static int minor = 0;
static dev_t devno;
struct device *class_dev = NULL;
struct class *cls;


static int hello_open (struct inode *inode, struct file *filep)
{
	printk("hello_open()\n");
	return 0;
}
static int hello_release (struct inode *inode, struct file *filep)
{
	printk("hello_release()\n");

	return 0;
}

#define KMAX_LEN 32
char kbuf[KMAX_LEN+1] = "kernel";


//read(fd,buff,40);

static ssize_t hello_read (struct file *filep, char __user *buf, size_t size, loff_t *pos)
{
	int error;

	
	if(size > strlen(kbuf))
	{
		size = strlen(kbuf);
	}

	if(copy_to_user(buf,kbuf, size))
	{
		error = -EFAULT;
		return error;
	}

	return size;
}
//write(fd,buff,40);
static ssize_t hello_write (struct file *filep, const char __user *buf, size_t size, loff_t *pos)
{
	int error;

	if(size > KMAX_LEN)
	{
		size = KMAX_LEN;
	}
	memset(kbuf,0.sizeof(kbuf));
	if(copy_from_user(kbuf, buf, size))
	{
		error = -EFAULT;
		return error;
	}
	printk("%s\n",kbuf);
	return size;
}


static struct file_operations hello_ops = 
{
	.open = hello_open,
	.release = hello_release,
	.read = hello_read,
	.write = hello_write,
};
static int hello_init(void)
{
	int result;
	
	printk("hello_init \n");
	result = register_chrdev( major, "hello", &hello_ops);
	if(result < 0)
	{
		printk("register_chrdev fail \n");
		return result;
	}
	cls = class_create(THIS_MODULE, "hellocls");
	if (IS_ERR(cls)) {
		printk(KERN_ERR "class_create() failed for cls\n");
		result = PTR_ERR(cls);
		goto out_err_1;
	}
	devno = MKDEV(major, minor);
	
	class_dev = device_create(cls, NULL, devno, NULL."hellodev");
	if (IS_ERR(class_dev)) {
		result = PTR_ERR(class_dev);
		goto out_err_2;
	}
	
	return 0;

out_err_2:
	class_destroy(cls);
out_err_1:
	unregister_chrdev(major,"hello");
	return 	result;
}
static void hello_exit(void)
{
	printk("hello_exit \n");
	device_destroy(cls, devno);
	class_destroy(cls);
	unregister_chrdev(major,"hello");
	return;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
//proc/devices

Copy the code

Note that we need to write the following Makefile:

ifneq ($(KERNELRELEASE),)
obj-m:=hello.o
else
KDIR :=/home/peng/linux3.14
PWD  :=$(shell pwd)
all:
	make -C $(KDIR) M=$(PWD) modules
clean:
	rm -f *.ko *.o *.mod.o *.symvers *.cmd  *.mod.c *.order
endif
Copy the code

For a full explanation of makefiles, see our previous article “Teach Linux Drivers 1- Modular Programming” where the kernel path is:

KDIR :=/home/peng/linux3.14
Copy the code

It must be the kernel source root we just compiled.

When compiled, the program can be placed in another directory:

View file properties using the file command, which is based on ARM. This module file is the driver module that matches the previously compiled kernel. If the kernel version of the development board is the same as the version number compiled above, this module file can be insmod on the development board.

2. Compile to the kernel

Steps:

  • 1) Copy files

If we want to compile the driver directly into the kernel, we must copy hello.c to a directory in the kernel.

Character devices can be considered in the following directories:

linux3.14/drivers/char
Copy the code

  • 2) Modify the Makefile
root@ubuntu:/home/peng/linux3.14/drivers/char# vim Makefile 
Copy the code

Modified as follows:

This line determines whether to compile the hello.c file based on the CONFIG_HELLO macro.

  • 3) Modify Kconfig

8 tristate means that the module finally has 3 options. Empty * M 9 means that the module depends on the module. If ARCH_EXYNOS4 module is not selected, Then the HELLO module will not be compiled into kernel 10 help messages

  • 4) Reconfigure

perform

make menuconfig
Copy the code

The configuration page is displayed.

Enter/to find the module location by keyword.

The location of the module file we added:

According to the path

-> Device Drivers 
   -> Character devices
Copy the code

Find the module configuration path we just found

Angle brackets here, because the property we set is tristate move to Help, you can see the Help information we filled in earlier

We can press the space bar to set it to * and compile it into the kernel.

Select Save,

Then click Exit 2 more times to Exit.

  • 5) Recompile the kernel
root@ubuntu:/home/peng/linux3.14# make uImage
Copy the code

In this way, our module is compiled into the newly generated kernel module file.

Added 3.

The last video was really about generatingCONFIG_HELLO=yThis defines the information and saves it to a. Config file in the kernel root directory.In fact, if we do not modify Kconfig, we can directly add the macro definition in. Config.

That’s all for today. What are you waiting for? Let’s get to practice.

The virtual machine used in the article, called cross-compilation tool, as well as the source code, you can pay attention to the public number, background reply ubuntu, can be obtained.