系统调用理论知识
什么是系统调用?
如open(), close(), read(), write()
等等。Linux被分为用户空间和内核空间,在内核空间我们实现了某个函数,这个函数要在用户空间被引用到;像read()
函数的实现体不在C库也不在其他应用程序,而是来自于内核空间。
系统调用工作流程
应用程序通过系统调用从用户空间进入内核空间需要swi
(软中断ARM指令)来切换到内核空间,在内核中系统调用中的每个函数都被编号,把编号赋给r7
,内核代码首先从r7
取出编号,利用编号作为偏移找到相应系统调用函数。
内核空间的系统调用函数实现
我们将新的系统调用函数实现写入一个内核文件printk.c中:
extern void my_syscall(void)
{
printk (“this is a new syscall!\n”);
}
通过<linux/unistd.h>我们找到<asm/unistd.h>
然后在unistd.h中添加新的系统调用函数(arch/arm/include/asm/unistd.h)
#define __NR_pk (__NR_SYSCALL_BASE+365)
在系统调用列表最后添加:注意偏移量必须与call.S中的一致。
在相关处理器的calls.S中追加如下函数:(arch/arm/kernel/calls.S)
添加如下代码:CALL(my_syscall)
然后重新编译内核并烧写到开发板:
[root@redhat6 linux-mini2440]# make uImage ARCH=arm CROSS_COMPILE=arm-linux-
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
UIMAGE arch/arm/boot/uImage
Image Name: Linux-2.6.32.2-FriendlyARM
Created: Mon Oct 31 19:43:02 2016
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 2287096 Bytes = 2233.49 kB = 2.18 MB
Load Address: 30008000
Entry Point: 30008000
Image arch/arm/boot/uImage is ready
[root@redhat6 linux-mini2440]# cp arch/arm/boot/uImage /tftpboot/
cp: overwrite `/tftpboot/uImage'? y
[root@redhat6 linux-mini2440]#
用户空间的系统调用函数实现
编写应用层系统调用函数:
extern void pk(void) //系统调用用户空间接口函数
{
__asm__ volatile (
"ldr r7,=365\n"
"swi\n"
:
:
:"memory"
);
}
int main (void)
{
pk();//测试程序使用接口函数来调用新的系统调用
return 0;
}
静态交叉编译开发板测试程序:
[root@redhat6 test]# arm-linux-gcc -static syscall.c -Os -o syscall
[root@redhat6 test]# ls -sh
total 576K
572K syscall 4.0K syscall.c
[root@redhat6 test]# cp syscall /home/redhat6/rootfs/
cp: overwrite `/home/redhat6/rootfs/syscall'? y
[root@redhat6 test]#
应用程序在开发板上测试:
# ls
bin hello.ko initrd media sbin syscall usr
dev home lib mnt sqlite3 tmp var
etc init linuxrc proc sys uImage
# ./syscall
info: this is a new syscall
#