《Linux内核设计与实现》学习【3】——系统调用

本文详细解析了ARM系统调用的工作原理,包括硬件抽象接口、权限管理和源码层面的异常处理流程。通过实例展示了如何添加新的系统调用,从内核到用户空间的完整过程。适合深入理解Linux内核与系统调用机制的开发者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 作用

用户–>系统调用–>硬件。
作用:
  1)为用户空间提供了一种硬件的抽象接口
  2)保证安全性,内核可以根据权限、用户类型等对需要的访问进行裁决

2 源码分析

  以arm平台代码为例。
  发生系统调用时,会通过swi指令,陷入到内核态。swi指令格式

SWI{cond} immed_24

  然后进入异常向量vector_swi,在arch/arm/kernel/entry-common.S中

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


#if defined(CONFIG_OABI_COMPAT)

	ldr	r10, [lr, #-4]			@ get SWI instruction   //获取swi指令码
  A710(	and	ip, r10, #0x0f000000		@ check for SWI		) //检测是否是正确的swi指令,在s3c2440手册中有描述格式
  A710(	teq	ip, #0x0f000000						)
  A710(	bne	.Larm710bug						)
  ...
  enable_irq

	get_thread_info tsk
	adr	tbl, sys_call_table		@ load syscall table pointer  //tbl数组基地址
	ldr	ip, [tsk, #TI_FLAGS]		@ check for syscall tracing
	...
	bic	scno, scno, #0xff000000		@ mask off SWI op-code //清除高8位
	eor	scno, scno, #__NR_SYSCALL_BASE	@ check OS number
	...
	ldrcc	pc, [tbl, scno, lsl #2]		@ call sys_* routine //将对应调用号的函数地址赋给pc

  在/arch/arm/include/asm中

#define __NR_OABI_SYSCALL_BASE	0x900000

#if defined(__thumb__) || defined(__ARM_EABI__)
#define __NR_SYSCALL_BASE	0
#else
#define __NR_SYSCALL_BASE	__NR_OABI_SYSCALL_BASE
#endif

  __NR_SYSCALL_BASE为0x900000

2 增加系统调用

  在arch/arm/kernel/calls.S中,在最后添加

		...
		CALL(sys_rt_tgsigqueueinfo)
		CALL(sys_perf_event_open)
		CALL(sys_hello) //增加的

  在arch/arm/include/asm/unistd.h中增加

#define __NR_hello			(__NR_SYSCALL_BASE+365)

  在fs/read_write.c中增加

asmlinkage void sys_hello(const char __user * buf, int count)
{
	char ker_buf[100];
	if (buf)
	{
		copy_from_user(ker_buf, buf, (count < 100) ? count : 100);
		ker_buf[99] = '\0';
		printk("sys_hello: %s\n", ker_buf);
	}
}

  include/linux/syscalls.h文件里添加声明

asmlinkage void sys_hello(const char __user * buf, int count);

  测试程序

#include <errno.h>
#include <unistd.h>
//#include <sysdep.h>

//#if defined(__thumb__) || defined(__ARM_EABI__)
//#define __NR_SYSCALL_BASE	0
//#else
#define __NR_SYSCALL_BASE	0x900000
//#endif

void hello(char *buf, int count)
{
	/* swi */

	asm ("mov r0, %0\n"   /* save the argment in r0 */
	     "mov r1, %1\n"   /* save the argment in r0 */
		 "swi %2\n"   /* do the system call */
		 :	
		 : "r"(buf), "r"(count), "i" (__NR_SYSCALL_BASE + 365)
		 : "r0", "r1");
}

int main(int argc, char **argv)
{
	printf("in app, call hello\n");
	hello("www.100ask.net", 15);
	return 0;
}

  编译

arm-linux-gcc -static syscall.c -o syscall

  在开发板运行,能看到输出信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值