Linux kernel interpretation

xiaoxiao2021-03-06  81

Linux kernel interpretation

For a lot of Linux enthusiasts, it is interested in the kernel but does not follow the mouth, this article aims to introduce a way to interpret the Linux kernel source code, not to explain the complex kernel mechanism of Linux;

One. Document organization of the core source program:

1. The Linux core source program is usually installed under / usr / src / linux, and it has a very simple number agreement: any even core (for example, 2.0.30) is a core of stable release, and any odd core (For example, 2.1.42) is a core of development.

Based on stable 2.2.5 source code, the second part of the implementation platform is Redhat Linux 6.0.

2. The document of the core source program is organized by the tree structure. You will see such a directory in the top of the source tree.

● ARCH: The Arch subdirectory includes all core code related to the architecture. Each subdirectory represents a supported architecture, such as the I386 is a subdirectory for Intel CPUs and compatible architectures. The PC is generally based on this directory;

● Include: The incrude subdirectory includes most of the header files that need to be compiled. The header with the platform is in the include / Linux subdirectory, with the Intel CPU-related header files in the include / SCSI directory, and the include / SCSI directory is the header file directory of the SCSI device;

● init: This directory contains the core initialization code (Note: not a system boot code), contains two files main.c and version.c, which is a very good starting point for studying how the core works.

● MM: This directory includes all memory management code independent of the CPU architecture, such as page-oriented management memory allocation and release, etc .; and architectural memory management code is located in Arch / * / mm /, such as Arch / I386 / mm / fault.c

● kernel: The main core code, this directory implements most Linux system kernel functions, the most important files are SCHED.C; the same, and the architecture related code in Arch / * / kernel;

● Drivers: Place all device drivers for the system; each driver also occupies a subdirectory: such as / block for block device drivers, such as IDE (Ide.c). If you want to see how all the devices that may contain a file system is initialized, you can see Device_Setup () in drivers / block / genhd.c. It not only initializes the hard disk, but also initializes the network, because the network is required to install the NFS file system: If the network places the core library code; NET, core and network related code; IPC, this directory contains the code between the core process FS, all file system code and various types of file operation code, each subdirectory supports a file system, such as FAT and EXT2;

Scripts, this directory contains scripting files for configuring cores.

Generally, in each directory, there is a .depend file and a Makefile file, both files are compiled auxiliary files, carefully read these two files to clarify the links and relying on each file. Very help; and, in some directory, there is a readme file, it is some instructions for files in this directory, which is also conducive to our understanding of kernel source.

two. Interpretation of actual combat: adding a system call for your kernel

Although Linux's kernel source code is well organized, scientifically, the files associated with the function are placed in the same subdirectory, which makes the program more readable. However, Linux's kernel source code is too big and very complicated, even with a very reasonable file organization method, there is still a lot of associations between files in different directories, and some of the code to analyze the core will usually view other few more. A related file, and may not be in the same subdirectory. The huge complexity of the system is complex, which may be the main reason for many people. Of course, the return brought about by this daunting labor is also very fascinating: you can not only learn from middle school to many computers (as guidance of the system will mention below), experience the entire operation The exquisiteness of the system architecture and the skill of the algorithm; and more importantly, in the analysis process of the source code, you will be able to specialize in a point, and even, as long as After analyzing one quarter code, you will deeply understand that what kind of code is written by a professional programmer, what code is a hobby written.

In order to make the reader better experience to this feature, the following will give a specific kernel analysis example, hoping to pass this example, so that the reader has some specific understandings for Linux kernel, from the readers can learn some pairs Analysis method of the kernel.

The following is the analysis example:

[One] Operation Platform:

Hardware: CPU Intel Pentium II;

Software: Redhat Linux 6.0; Nuclear version 2.2.5 [2] Related kernel source code analysis:

1. Boot and initialization of the system: There are several ways to boot in the Linux system: common Lilo, Loadin boot and Linux bootstrap boot

(Bootsect-loader), the latter's corresponding source program is Arch / I386 / Boot / Bootsect.s, which is a real-mode assembler, limited to the space, no analysis, no matter which guidance method, finally want to jump Go to Arch / i386 / kernel / setup.s, setup.s is mainly initialization in time mode, preparing for the system to enter the protection mode; Since then, the system performs Arch / I386 / Kernel / Head.s (after compression The kernel stored must first execute Arch / i386 / boot / compressed / head.s); a assembler setup_idt defined in Head.s, which is responsible for establishing a 256 IDT table (Interrupt Descriptor Table), this table is saved All inlet addresses of all divisions and interrupts; including the system calling the header address of the system_call; of course, other initialization works;

2. The first kernel program for the system is initialized, the first kernel program asmlinkage void __init start_kernel (void) is defined

/usr/src/linux/init/main.c, which calls a function in USR / SRC / Linux / Arch / i386 / kernel / traps.c

VOID __INIT TRAP_INIT (VOID) Sets the entry address of the individual traps and the interrupt service program to the IDT table, where the system calling the total controller system_cal is one of the interrupt service programs; the void __init trap_init (void) function passes a macro

SET_SYSTEM_GATE (Syscall_Vector, & System_Call); hooks the entry of the system calling the total control program on the interrupt 0x80;

Where syscall_vector is a constant 0x80 defined in /usr/src/linux/arch/i386/kernel/irq.h; and system_call is the entry address of the interrupt presser program; the interrupt total control program is defined in / usr /Src/linux/Arch/i386/kernel/entry.s; 3. Interrupt General Controller is primarily responsible for saving the status before the processor executes system calls, verify that the current call is legal, and causes the processor to jump according to the system call Go to the entry of the corresponding system service routine saved in the sys_call_table table; return the processor status to the user program after returning from the system service routine;

The system call vector defines in /usr/src/linux/include/sm-386/unistd.h; SYS_CALL_TABLE table is defined in /usr/src/linux/Arch/i386/kernel/entry.s; at the same time / User programming interfaces of system calls are also defined in USR / SRC / Linux / INCLUDE / ASM-386 / Unistd.h;

4. It can be seen that Linux system calls are also like the INT 21H interrupt service of the DOS system, which interrupts the 0x80 interrupt as the total entry, and then goes to the entrance address of the various interrupt service routines saved in the sys_call_table table to form each Different interrupted services;

It is understood by the above source code analysis. To add a system call, you must add an item in the sys_call_table table, and save your own system service routine's entry address, then recompile the kernel, of course, the system service routine is Indispensable.

This can be seen in this version of the Linux kernel source program, the source program file related to the system calls includes the following:

1. Arch / i386 / boot / bootsect.s

2. Arch / i386 / kernel / setup.s

3. Arch / i386 / boot / compressed / head.s

4. Arch / i386 / kernel / head.s

5. Init / main.c

6. Arch / i386 / kernel / traps.c

7. Arch / i386 / kernel / entry.s

8. Arch / i386 / kernel / Irq.h

9. INCLUDE / ASM-386 / Unistd.h

Of course, this is just a few main files involved. In fact, increasing system calls really want to modify file only include both include / ASM-386 / UNISTD.H and Arch / I386 / Kernel / Entry.s;

[3] Modification to the kernel source code:

1. Increase the system service routine in kernel / sys.c as follows:

ASMLINKAGE INT SYS_ADDTOTAL (Int Numdata)

{

INT i = 0, enddata = 0;

While (i <= numdata)

Enddata = i ;

Return Enddata;

}

This function has an INT type entry parameter NumData, and returns the accumulated value from 0 to NumData; of course, you can also put the system service routine in your own defined file or other files, just to explain it in the corresponding file. ;

2. Add the entry address of the ASMLINKAGE INT SYS_ADDTOTAL (INT) to the SYS_CALL_TABLE table:

The last few line source code in Arch / i386 / kernel / entry.s is modified:

...

.long symbol_name (sys_sendfile)

.long symbol_name (SYS_NI_SYSCALL) / * streams1 * /

.long symbol_name (SYS_NI_SYSCALL) / * streams2 * /

.long symbol_name (sys_vfork) / * 190 * /

.rept nr_syscalls-190.long symbol_name (SYS_NI_SYSCALL)

.endr

After modification: ... ...

.long symbol_name (sys_sendfile)

.long symbol_name (SYS_NI_SYSCALL) / * streams1 * /

.long symbol_name (SYS_NI_SYSCALL) / * streams2 * /

.long symbol_name (sys_vfork) / * 190 * /

/ * Add by i * /

.long symbol_name (sys_addtotal)

.rept nr_syscalls-191

.long symbol_name (SYS_NI_SYSCALL)

.endr

3. Put the vector corresponding to the added sys_call_table entry to include the necessary statements in include / ASM-386 / Unistd.h for user processes and other system process queries or calls:

Added part /usr/src/linux/include/sm-386/unistd.h file is as follows:

...

#define __nr_sendfile 187

#define __nr_getpmsg 188

#define __nr_putpmsg 189

#define __nr_vfork 190

/ * Add by i * /

#define __nr_addtotal 191

4. The test program (Test.c) is as follows:

#include

#include

_SysCall1 (int, addtotal, int, num)

Main ()

{

INT I, J;

DO

Printf ("Please Input A Number / N);

While (Scanf ("% D", & I) == EOF);

IF ((j = addtotal (i)) == - 1)

Printf ("Error Occurred In syscall-addtotal (); / n");

Printf ("Total from 0 to% D IS% D / N", I, J);

}

Compiling the new kernel after the modified core, and boots it as a new operating system. After running a few programs, you can find everything is normal; compile the test program under the new system (* Note: This is not provided due to the original core System call, so only after compiled new kernels, this test program can be compiled), and the operation is as follows:

$ GCC -O Test Test.c

$. / TEST

Please Input a Number

36

Total from 0 to 36 IS 666

It can be seen that the revision is successful;

Moreover, further analysis of the relevant source code is known that in this version of the core, from /usr/src/linux/Arch/i386/kernel/entry.s

The settings for the SYS_CALL_TABLE table can be seen in the file, and there are several system calls that call the service routines defined in /usr/src/linux/kernel/sys.c:

ASMLINKAGE INT SYS_NI_SYSCALL (VOID)

{

Return -enosys;

}

This is, for example, Articles 188 and 189.

...

.long symbol_name (sys_sendfile)

.long symbol_name (SYS_NI_SYSCALL) / * streams1 * /

.long symbol_name (SYS_NI_SYSCALL) / * streams2 * /

.long symbol_name (sys_vfork) / * 190 * /

...

And these two in the file /usr/src/linux/include/sm-386/unistd.h is as follows: ...

#define __nr_sendfile 187

#define __nr_getpmsg 188 / * Some People Actual Want Street * /

#define __nr_putpmsg 189 / * Some People Actually Want Street * /

#define __nr_vfork 190

It can be seen that in this version of the kernel source code, since the ASMLINKAGE INT SYS_NI_SYSCALL (Void) function does not perform any operation, several system calls, including getPMSG, PUTPMSG are not performed, that is, to be expanded Air conditioning; but they still take up the sys_call_table entry, and it is estimated that this is the designer to arrange for the convenience of the expansion system; so simply add the corresponding service routine (such as increasing service routines getMSG or PUTPMSG), Give the role of increasing system calls.

Conclusion: Of course, for a huge complex Linux kernel, an article is far less, and the code related to the system call is only a very small part of the kernel; but the important method, master the method; The analysis is just a role of guidance, and the true analysis is to wait for the reader's own efforts. :)

转载请注明原文地址:https://www.9cbs.com/read-95340.html

New Post(0)