Do you know the Arm Linux system call process?

Publisher:创意狂想Latest update time:2020-08-04 Source: elecfansKeywords:Arm Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

The Linux system implements most of the interfaces between user-mode processes and hardware devices by issuing system calls to the kernel.

System calls are services provided by the operating system. User programs use various system calls to reference various services provided by the kernel. The execution of system calls causes user programs to fall into the kernel, and the falling action is completed by the swi soft interrupt.


1. Users can use system calls in two ways:

The first way is through C library functions, including system call encapsulation functions and other common functions in the C library.

The second way is to use the _syscall macro. In kernels prior to version 2.6.18, there are seven _syscall macros defined in the include/asm-i386/unistd.h file, namely:

_syscall0(type,name) _syscall1(type,name,type1,arg1) _syscall2(type,name,type1,arg1,type2,arg2) _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6)


Among them, type represents the return value type of the generated system call, name represents the name of the system call, typeN and argN represent the type and name of the Nth parameter respectively, and their number is the same as the number after _syscall.


The purpose of these macros is to create a function named name, and the number following _syscall indicates the number of parameters of the function.


For example, the sysinfo system call is used to obtain overall system statistics, and is defined using the _syscall macro:

_syscall1(int, sysinfo, struct sysinfo *, info);

The expanded form is:

int sysinfo(struct sysinfo * info) {   long __res;   __asm__ volatile("int $0x80" : "=a" (__res) : "0" (116),"b" ((long)(info)));   do {     if ((unsigned long)(__res) >= (unsigned long)(-(128 + 1)))     {       errno = -(__res);       __res = -1;     }     return (int) (__res);   } while (0); }


It can be seen that _syscall1(int, sysinfo, struct sysinfo *, info) is expanded into a function named sysinfo. The original parameter int is the return type of the function, and the original parameters struct sysinfo * and info constitute the parameters of the new function respectively.


Use the _syscall macro to define the required system call in the program file, and then you can call the system call directly through the system call name in the following code. The following is an example of using the sysinfo system call.


Code Listing 5.1 Example of using the sysinfo system call

#include #include #include #include /* for struct sysinfo */ _syscall1(int, sysinfo, struct sysinfo *, info); int main(void) {   struct sysinfo s_info;   int error;  error = sysinfo(&s_info);   printf("code error = %d/n", error);   printf("UpTIme = %lds/nLoad:       1 min %lu / 5 min %lu / 15 min %lu/n"       "RAM: total %lu / free %lu / shared %lu/n"       "Memory in buffers = %lu/nSwap: total %lu / free %lu/n"   "Number of processes = %d/n",   s_info.upTIme,       s_info.loads[0], s_info.loads[1], s_info.loads[2],       s_info.totalram, s_info.freeram, s_info.sharedram, s_info.bufferram, s_info.totalswap, s_info.freeswap,       s_info.procs);   exit(EXIT_SUCCESS); }


However, since version 2.6.19, the _syscall macro has been abolished, and we need to use the syscall function to call the system call by specifying the system call number and a set of parameters.


The syscall function prototype is:

int syscall(int number, ...);

Where number is the system call number, followed by all the parameters of the system call in sequence. The following is an example of calling the getTId system call.


Code Listing 5.2 Example of using the getTId system call

#include #include #include #define __NR_gettid 224 int main(int argc, char *argv[]) { pid_t tid; tid = syscall(__NR_gettid); }

Most system calls include a SYS_ symbol constant to specify their mapping to the system call number, so line 10 above can be rewritten as:

tid = syscall(SYS_gettid);


2 Differences between system calls and application programming interfaces (APIs)

The difference between an application programming interface (API) and a system call is that the former is just a function definition that describes how to get a given service, while the latter is an explicit request to the kernel via a software interrupt. The POSIX standard is for APIs, not for system calls. Unix systems provide programmers with many API library functions. Some of the APIs defined by the standard C library libc refer to wrapper routines (whose sole purpose is to issue system calls). Usually, there is one wrapper routine for each system call, and the wrapper routines define the API used by the application. The reverse is not true, and an API does not necessarily correspond to a specific system call. From the programmer's point of view, the difference between APIs and system calls is irrelevant: the only relevant things are the function name, the types of arguments, and the meaning of the return code. However, from the kernel designer's point of view, the difference does matter, because system calls belong to the kernel, while user-mode library functions do not belong to the kernel.


Most of the wrapper routines return an integer whose meaning depends on the corresponding system call. A return of -1 usually means that the kernel cannot satisfy the process's request. Failure of a system call handler may be caused by invalid parameters, lack of available resources, hardware problems, etc. The errno variable defined in the libd library contains the specific error code. Each error code is defined as a constant macro.


When a process in user mode calls a system call, the CPU switches to kernel mode and begins executing a kernel function. Because the kernel implements many different system calls, the process must pass a parameter called the system call number to identify the desired system call. All system calls return an integer value. These return values ​​are different from the conventions for return values ​​of wrapper routines. In the kernel, an integer or 0 indicates that the system call has completed successfully, while a negative number indicates an error condition. In the latter case, this value is a negative error code that must be returned to the application in the errno variable.


3 System call execution process

ARM Linux system uses SWI instruction to enter kernel space from user space. Let's first understand this SWI instruction. SWI instruction is used to generate software interrupt, so as to realize the transition from user mode to supervisor mode. CPSR is saved to SPSR of supervisor mode, and execution is transferred to SWI vector. SWI instruction can also be used in other modes, and the processor switches to supervisor mode in the same way. The instruction format is as follows:

SWI{cond} immed_24

in:

immed_24 24-bit immediate value, the value is an integer between 0 and 16777215.

When using the SWI instruction, the following two methods are usually used for parameter passing. The SWI exception handler can provide related services. Both methods are user software agreements. The SWI exception interrupt handler must obtain a 24-bit immediate value by reading the SWI instruction that caused the software interrupt.


1) The 24-bit immediate value in the instruction specifies the type of service requested by the user, and the parameters are passed through general registers. For example:

MOV R0,#34SWI 12

2) The 24-bit immediate value in the instruction is ignored. The service type requested by the user is determined by register R0 only, and the parameters are passed through other general registers. For example:

MOV R0, #12MOV R1, #34SWI 0

In the SWI exception handler, the steps to remove the SWI immediate value are: first determine whether the SWI instruction of a soft interrupt is an ARM instruction or a Thumb instruction, which can be obtained by accessing the SPSR; then obtain the address of the SWI instruction, which can be obtained by accessing the LR register; then read the instruction and decompose the immediate value (lower 24 bits).


Entering system call from user space

Normally, the code we write calls the system call through the encapsulated C lib. Take the open function in the 0.9.30 version of uClibc as an example to trace how this encapsulated function calls the system call step by step. It is defined in include/fcntl.h:

# define open open64

open is actually just an alias for open64.

In libc/sysdeps/linux/common/open64.c you can see:

extern __typeof(open64) __libc_open64;extern __typeof(open) __libc_open;

It can be seen that open64 is just an alias of __libc_open64, and the __libc_open64 function is defined in the same file:

libc_hidden_proto(__libc_open64)int __libc_open64 (const char *file, int oflag, ...){ mode_t mode = 0; if (oflag & O_CREAT) { va_list arg; va_start (arg, oflag); mode = va_arg (arg, mode_t); va_end (arg); } return __libc_open(file, oflag | O_LARGEFILE, mode);}libc_hidden_def(__libc_open64)

Finally, __libc_open64 calls the __libc_open function, which is defined in the file libc/sysdeps/linux/common/open.c:

libc_hidden_proto(__libc_open)int __libc_open(const char *file, int oflag, ...){ mode_t mode = 0; if (oflag & O_CREAT) { va_list arg; va_start (arg, oflag); mode = va_arg (arg, mode_t); va_end (arg); } return __syscall_open(file, oflag, mode);}libc_hidden_def(__libc_open)

_syscall_open is defined in the same file:

static __inline__ _syscall3(int, __syscall_open, const char *, file, int, flags, __kernel_mode_t, mode)

In the file libc/sysdeps/linux/arm/bits/syscalls.h, you can see:

#undef _syscall3#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) type name(type1 arg1,type2 arg2,type3 arg3) { return (type) (INLINE_SYSCALL(name, 3, arg1, arg2, arg3)); }


This macro actually completes the work of defining a function. The first parameter of this macro is the return value type of the function, the second parameter is the function name, and the subsequent parameters are the function parameter types and parameter names as indicated by its parameter name. __syscall_open is actually:

[1] [2] [3] [4]
Keywords:Arm Reference address:Do you know the Arm Linux system call process?

Previous article:ARM assembly and C mixed programming
Next article:Detailed introduction to building a cross-compilation toolchain for ARM Linux

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号