1 The role of system calls
The Linux kernel has a set of subroutines for implementing various system functions, called system calls, such as read, write, open, etc. Users can call them in their own applications through system call commands. From a certain perspective, system calls and ordinary function calls are very similar. The difference is that system calls are provided by the operating system core and run in kernel mode, while ordinary function calls are provided by function libraries or users themselves and run in user mode. In fact, many standard C language functions that we are accustomed to are implemented on the Linux platform through system calls. Therefore, if you want to have a deep understanding of the underlying principles of the system, you must master the preliminary requirements for various system calls.
2 How system calls work
We know that general processes cannot access the kernel. System calls are the only legal way for user space to access kernel space. In the early days, Linux used the OABI method to pass the system call number. Now Linux uses the new EABI (Embedded) method to pass the system call number. We mainly understand the EABI method, and will not talk about the OABI method here. The current Android compiler arm-linux-androideabi-gcc uses the EABI method. The process of this new system call method is as follows:
1. Store the syscall number in the r7 register.
2. Execute the swi instruction to jump to the soft interrupt and get the syscall number from r7.
Note that the soft interrupt mentioned here is supervisor call exception (svc). Since its original name was software interrupt (swi), the term soft interrupt has been used.
If there is a read function in the application and there is also a read function in the system call, how to find the read function in the kernel space from the application? You need to use the swi instruction. There are many system call functions in the kernel, such as read, write, open, etc. How does the kernel know which function is called? Here we need to use a register r7, which we will talk about later.
In the kernel source code, there is a file entry-common.S assembly code in archarmkernel. This code is the interface for the application to access the kernel. Some of the code is given below.
ENTRY(vector_swi)
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0 - r12
ARM( add r8, sp, #S_PC )
ARM( stmdb r8, {sp, lr}^ ) @ Calling sp, lr
THUMB( mov r8, sp )
THUMB( store_user_sp_lr r8, r10, S_SP ) @ calling sp, lr
mrs r8, spsr @ called from non-FIQ mode, so ok.
str lr, [sp, #S_PC] @ Save calling PC
str r8, [sp, #S_PSR] @ Save CPSR
str r0, [sp, #S_OLD_R0] @ Save OLD_R0
zero_fp
/*
* Get the system call number.
*/
#if defined(CONFIG_OABI_COMPAT)
/*The OABI method is used here
* If we have CONFIG_OABI_COMPAT then we need to look at the swi
* value to determine if it is an EABI or an old ABI call.
*/
#ifdef CONFIG_ARM_THUMB
tst r8, #PSR_T_BIT
movne r10, #0 @ no thumb OABI emulation
ldreq r10, [lr, #-4] @ get SWI instruction
#else
ldr r10, [lr, #-4] @ get SWI instruction
A710( and ip, r10, #0x0f000000 @ check for SWI )
A710( ip teq, #0x0f000000 )
A710( bne .Larm710bug )
#endif
#ifdef CONFIG_CPU_ENDIAN_BE8
rev r10, r10 @ little endian instruction
#endif
#elif defined(CONFIG_AEABI)
/*Here we use the EABI method
* Pure EABI user space always put syscall number into scno (r7).
*/
A710( ldr ip, [lr, #-4] @ get SWI instruction )
A710( and ip, ip, #0x0f000000 @ check for SWI )
A710( ip teq, #0x0f000000 )
A710( bne .Larm710bug )
#elif defined(CONFIG_ARM_THUMB)
/* Legacy ABI only, possibly thumb mode. */
tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs
addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in
ldreq scno, [lr, #-4]
#else
/* Legacy ABI only. */
ldr scno, [lr, #-4] @ get SWI instruction
A710( and ip, scno, #0x0f000000 @ check for SWI )
A710( ip teq, #0x0f000000 )
A710( bne .Larm710bug )
#endif
In the EABI method, we can see that the application system space puts the system call number in the r7 register, as shown below
The kernel needs to get this number, take the value of register r7 and put it into scno.
There is a sentence ldrcc pc, [tbl, scno, lsl #2] in the program. We will not look at other code parts for now.
This sentence indicates that the kernel takes out the syscall number in the r7 register through scno.
1 This instruction logically shifts scno left by 2 bits and adds it to tbl, and assigns the value stored at the result position to PC. PC = * (tbl + (scno << 2)).
2 tbl is the entry address of the system call table, and tbl can be regarded as a char array header. char tbl[] = {…….};
3 Because scno only means the number of the system call, not the actual address or relative address of the system call.
4 The actual address of each system call (that is, the function name) is .long x 32 bits, which requires four bytes to store.
5 scno logically shifts left by 2 bits, which means that the entry address of the required system call function is stored at the position offset by scno<<2 bytes on tbl. tbl[scno<<2] stores the entry address of the required system call function.
In entry-common.S, sys_call_table is called, which is actually the assembly code of calls.S. It stores the numbers of various system calls. The kernel code uses this number as an offset to find the corresponding system call. The code of calls.S is as follows. The system call starts from 0. The first system call is sys_reatart_syscall, and the second is sys_exit. Of course, these codes are specially defined by the Linux kernel writers. If we want to add our own system call functions, we can add them one by one at the end of these codes. The format is generally the same (sys_function name). For example, when you write a function named mem, when updating calls.S, just add CALL(sys_mem) in the code in sequence.
/* 0 */ CALL(sys_restart_syscall)
CALL(sys_exit)
CALL(sys_fork_wrapper)
CALL(sys_read)
CALL(sys_write)
/* 5 */ CALL(sys_open)
CALL(sys_close)
CALL(sys_ni_syscall) /* was sys_waitpid */
CALL(sys_creat)
CALL(sys_link)
In the unistd.h file, the system call program is basically written based on this header file. Every time a system call function is added, the unistd.h and calls.S files must be updated. The system call number also corresponds to the number in call.S. The code part is as follows. The function names we want to add are also added in the order in the code. Generally speaking, the format is —_NR function name.
Here you need to manually add #define __NR_mem at the end.
/*
* This file contains the system call numbers.
*/
#define __NR_restart_syscall (__NR_SYSCALL_BASE+ 0)
#define __NR_exit (__NR_SYSCALL_BASE+ 1)
#define __NR_fork (__NR_SYSCALL_BASE+ 2)
#define __NR_read (__NR_SYSCALL_BASE+ 3)
#define __NR_write (__NR_SYSCALL_BASE+ 4)
#define __NR_open (__NR_SYSCALL_BASE+ 5)
#define __NR_close (__NR_SYSCALL_BASE+ 6)
So far, the general process of Linux system calls is like this. The author has not gone into detail, but it is enough to understand this much for now, and then continue to work hard as you learn more.
Previous article:Character device driver (I)
Next article:DMA mechanism (based on S3C6410)
Recommended ReadingLatest update time:2024-11-16 13:03
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- TMS320C66x dual loop and multiple loop optimization summary
- 【TI recommended course】#TI millimeter wave radar technology introduction#
- 【micropython】STM32 will support arbitrary FS
- Global variables in embedded system programming
- PWM generated voltage calculation table
- Help, I need to exchange an E coin, I still need one
- The official WeChat group of the community has been established: you can chat about Microchip live broadcast and PIC microcontrollers
- C6000 Code Generation Tools - Compiler
- Analog Electronics Technology (US) Boylstad
- In that era...