Linux kernel interpretation entry (reposted)

xiaoxiao2021-03-05  30

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

Instead of explaining Linux complex kernel mechanism;

One. Document organization of the core source program:

1. Linux core source program is usually installed under / usr / src / linux, and it has a very simple number agreement: any even number of

Core (e.g., 2.0.30) is a steady core, while any odd core (such as 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 system

Structure, such as 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. Head file with platform-independent header in Include / Linux

In the subdirectory, the header related to the Intel CPU is in the include / ASM-I386 subdirectory, and the include / SCSI directory is related

Skull file directory of SCSI device;

● Init: This directory contains the core initialization code (Note: not the system's boot code), contains two files main.c and version.c,

This is a very good starting point to study how the core works.

● mm: This directory includes all memory management code independent of the CPU architecture, such as page-style storage management memory allocation and release, etc .;

The memory management code related to the architecture 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

Sched.c; Similarly, the code related to the architecture is in Arch / * / kernel;

● Drivers: Place all the device drivers for the system; each driver also occupies a subdirectory: If / block is block device

Drivers, such as IDE (IDE.c). If you want to see how the device that may contain the file system is initialized, you can see

DRIVERS / block / genhd.c device_setup (). It not only initializes the hard disk, but also initializes the network because NFS file is installed.

Network is required

Other: If the lib 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 compile

Used auxiliary files, read these two documents, which is very helpful to clarify the links and relying on each file; and in some directory

There is also a readme file, which 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 really 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 part of the code of the core is usually to view other related files, and may

These files are not in the same subdirectory.

The huge complexity of the system is complex, which may be the main reason for many people. Of course, this kind of worry

The return brought is also very fascinated: You can not only learn the underlying knowledge of many computers (as guidance of the system will say below),

Experience the exquisiteness of the entire operating system architecture and in solving a specific details, the algorithm is ingenious; and more importantly: in the source code analysis

In the process, you will be specialized at a point, the subtleties will be specialized; even after analyzing one quarter of the code, you will deeply understand what

The code is written by a professional programmer, what kind of code is written by a hobby.

In order to make the reader can better experience this feature, the following will give a specific kernel analysis instance, I hope to pass this example to make the reader to Linux.

The organization of the kernel has some specific understandings, and from the readers can learn some analytical methods for kernels.

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), and the latter's corresponding source program is Arch / I386 / Boot / Bootsect.s, which is a real-mode assembler, limited to

The space is here not to analyze; no matter which guidance method, finally want to jump to the Arch / I386 / kernel / setup.s, setup.s mainly

Initialization in time mode, prepare for the system to enter the protection mode; thereafter, the system performs Arch / I386 / Kernel / Head.s (compressed compression)

The kernel stored later must first execute Arch / I386 / boot / compressed / head.s); one assembler setup_idt defined in Head.s,

It is responsible for establishing a 256 Idt table (Interrupt Descriptor Table), which saves all the entrance addresses of divide and interrupts;

Including the system calling the entrance address of the total controller system_call; Of course, in addition to this, Head.s will make some other initialization work;

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 respective traps and the interrupt service program to the IDT table, where the system calls the presser program

System_cal is one of the interrupt service programs; void __init trap_init (void) function passes a macro

SET_SYSTEM_GATE (syscall_vector, & system_call); hooks the entry of the system calling the presser program on the interrupt 0x80; syscall_vector is defined in /usr/src/linux/arch/i386/kernel/irq.h in a constant 0x80; and system_call

That is, it is the entrance address of the interrupt presser program; the interrupt total control program is defined in the assembly language in /usr/src/linux/Arch/i386/kernel/entry.s;

3. The interrupt prescription is mainly responsible for saving the status before the processor executes the system call, and the current call is legal, and the vector is called according to the system.

Jump 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 is defined in /usr/src/linux/include/ASM-386/unistd.h; SYS_CALL_TABLE table is defined

/usr/src/linux/Arch/i386/kernel/entry.s; at the same time /usr/src/linux/include/ASM-386/unistd.h

The user programming interface of the system call is also defined;

4. It can be seen that Linux system calls are also like the INT 21H interrupt service of the DOS system, which interrupt 0x80 as the total entry, then

Go to the entrance address of the various interrupt service routines saved in the sys_call_table table, form a variety of interrupt services;

It can be seen from the above source code analysis. To add a system call, you must add an item in the sys_call_table table, and save yourself.

The system service routine's entry address, then recompile the kernel, of course, the system service routine is essential.

This can be seen in this version of the Linux kernel source <2.2.5>, the source program file related to the system call 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 files only 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, the system service routine can be

In a defined file or other file, it just wants 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, in include / ASM-386 / UnisTd.h, for

User processes and other system processes 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 Numbern");

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 new kernel and guides it as a new operating system. After running a few programs, you can find everything is normal; under the new system

Compiling the test program (* Note: Due to the original kernel, this system is not provided, only the test program can only

It may be compiled), 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

As can be seen in the file, the settings of the SYS_CALL_TABLE table can be seen that there are several system calls to the service routines are defined.

/usr/src/linux/kernel/sys.c in the same function:

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 are declared 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,

Therefore, several system calls, including getpmsg, putpmsg are not in any operation, that is, the air conditioner to be expanded; but they

But still occupy the sys_call_table entry, which is estimated that the designers are arranged in order to facilitate the expansion of the system; so it only needs to increase the corresponding

Service routines (such as increasing service routines getMSG or PUTPMSG) can achieve increased system calls.

Conclusion: Of course, for a huge complex Linux kernel, an article is far less enough, and the code related to the system call is only the kernel.

Partial part; but important is how the method, master the analysis method; so the above analysis is just a boot role, and the true analysis is still waiting

Readers' own efforts.

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

New Post(0)