创建简单的Kernel System Call

本文详细介绍了如何在Linux内核中创建自定义的System Call,从创建源文件,添加Makefile内容,定义System Call原型,更新System Call Table,到编译内核并进行用户空间测试。关键步骤包括在特定目录下创建源文件,添加System Call原型到头文件,更新对应架构的System Call Table,并在用户空间中通过系统调用号调用新添加的System Call。

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

本篇是接着上一篇<编译Linux Kernel – Version 4.9.13>写的。

1. 创建system call 源文件

在下载了kernel的源代码并且解压后,进入根目录下的kernel文件夹,在里面创建文件hello.c

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/linkage.h>

asmlinkage long sys_hello(long a, long b){
   
	long sum = a + b;
	printk("hello world\n");
	printk("the sum is %d\n",sum);
	return 0;
	//return -EINVAL;
}
<think>好的,我现在需要回答用户关于系统调用(system call接口的问题。用户之前已经询问过用户模式内核模式,所以这次的问题应该是在那个基础上的延伸。首先,我应该先明确系统调用接口的定义,然后详细解释它们之间的关系区别。 系统调用是用户程序与操作系统内核之间的桥梁,允许用户程序请求内核的服务,比如文操作、进程控制等。而接口在这里可能指的是操作系统提供给应用程序的API,比如POSIX标准或者Windows API,这些接口封装了系统调用的细节,使得开发者更方便地使用系统功能。 接下来需要分步骤解释。首先介绍系统调用的基本概念,包括它的作用、工作原理以及常见类型。然后解释接口,特别是操作系统接口编程接口的区别。需要举一些例子,比如Linux的系统调用表,或者Windows的API函数,这样用户更容易理解。 用户可能想知道系统调用接口是如何协作的,比如当应用程序调用一个库函数(如fopen)时,这个函数内部是如何触发系统调用(如open)的。这时候需要解释用户模式到内核模式的切换过程,以及参数传递的机制,比如通过寄存器或堆栈。 还要注意用户之前提到的系统级指令,比如使用正确的LaTeX格式。在回答中如果有数学表达式或代码,需要用$...$或$$...$$来标注。不过这个问题可能不需要太多数学公式,主要是文字描述,但如果有例子涉及参数传递或调用流程,可能需要用代码块或结构化的说明。 另外,用户希望结构清晰,逐步解决问题,所以需要分点说明,比如用“1. 基本概念”,“2. 工作流程”等小标题来组织内容。需要确保信息准确,比如系统调用的类型分为进程控制、文管理、设备管理等,这些分类是否正确,是否需要更详细的子类。 还需要考虑用户可能的后续问题,比如系统调用的性能开销,或者不同操作系统接口的差异,所以在回答中可以适当提及这些点,但不要过于深入,避免信息过载。例如,可以提到系统调用涉及模式切换带来的开销,以及现代操作系统如何优化,比如使用vsyscall或vdso机制。 最后,要确保用中文回答,语言简洁明了,避免专业术语过多,必要时进行解释。例如,解释“POSIX”是什么,或者“API”的全称应用场景。同时,检查是否有符合用户不可见的系统级指令,比如正确使用LaTeX格式,但在这个问题中可能应用较少,主要关注结构清晰正确性。 总结一下,回答的结构应该是先定义系统调用接口,然后分点详细说明各自的作用、类型、工作流程,接着举例说明它们之间的关系,最后可能补充一些设计意义或常见问题。需要确保覆盖用户的问题,同时连接之前关于用户模式内核模式的知识,形成连贯的体系。</think>--- ### **1. 系统调用(System Call)** **定义**:系统调用是**用户程序与操作系统内核交互的桥梁**。当应用程序需要访问硬或执行特权操作(如读写文创建进程)时,必须通过系统调用请求内核代为完成。 #### **核心特点**: - **权限提升**:触发从用户模式(User Mode)到内核模式(Kernel Mode)的切换。 - **标准化接口**:不同操作系统的系统调用名称参数可能不同,但功能分类相似(例如文操作、进程管理)。 - **安全性**:内核会验证请求的合法性(如检查内存地址是否越界)。 #### **常见系统调用类型**: | **类型** | **功能** | **示例(Linux)** | |----------------|-----------------------------|--------------------------| | **文操作** | 打开、读写、关闭文 | `open()`, `read()`, `write()` | | **进程控制** | 创建、终止、同步进程 | `fork()`, `exec()`, `wait()` | | **通信** | 进程间通信(IPC) | `pipe()`, `shmget()` | | **设备管理** | 控制硬设备(如打印机) | `ioctl()` | | **内存管理** | 分配或释放内存 | `brk()`, `mmap()` | --- ### **2. 接口(Interface)** **定义**:接口是**操作系统提供给用户程序的标准访问方式**,隐藏底层复杂细节,提供简洁、统一的操作方法。主要分为两类: #### **(1) 操作系统接口** - **系统调用接口**:直接暴露系统调用(如Linux的`syscall()`函数)。 - **库函数接口**:封装系统调用的高级函数(如C标准库的`fopen()`内部调用`open()`系统调用)。 #### **(2) 编程接口(API)** - **标准化规范**:例如POSIX(类Unix系统)、Win32 API(Windows),定义函数名、参数返回值。 - **跨平台兼容**:通过API适配不同系统的底层实现(如在Windows调用`CreateProcess()`,在Linux调用`fork()`+`exec()`)。 --- ### **3. 系统调用与接口的协作流程** **示例**:在Linux中调用`printf("Hello")` 1. **用户程序**:调用C标准库的`printf()`函数。 2. **库函数**:将字符串存入缓冲区,并调用`write()`系统调用。 3. **模式切换**:CPU从用户模式切换到内核模式。 4. **内核执行**:内核通过设备驱动将数据发送到显示器。 5. **返回结果**:内核完成操作后,切换回用户模式,程序继续执行。 > **关键点**:接口(如`printf()`)隐藏了底层系统调用(如`write()`)操作细节。 --- ### **4. 设计意义** - **抽象化**:用户无需关心硬差异(如不同磁盘控制器)。 - **安全性**:通过接口限制直接访问硬,防止程序恶意操作。 - **可移植性**:同一API可在不同系统上实现(如POSIX兼容的程序可移植到LinuxmacOS)。 --- ### **5. 常见问题** 1. **为什么需要库函数而不直接使用系统调用?** - 系统调用通常更底层且参数复杂,库函数提供简化封装(如`fopen()`比`open()`更易用)。 - 部分库函数可能组合多个系统调用(如`printf()`涉及内存分配`write()`)。 2. **系统调用的性能开销来自哪里?** - 模式切换需要保存/恢复寄存器状态(约数百CPU周期)。 - 现代优化:Linux的`vdso`机制允许部分系统调用无需切换模式(如获取时间)。 3. **不同操作系统的接口差异如何解决?** - 通过中间层(如Wine在Linux运行Windows程序)或标准化API(如Java虚拟机屏蔽系统差异)。 --- ### **示意图:接口与系统调用的分层结构** ``` +-----------------------+ | 应用程序(用户模式) | → 调用库函数接口(如`printf()`) +-----------------------+ | 标准库(如glibc) | → 封装系统调用(如调用`write()`) +-----------------------+ | 系统调用接口 | → 触发模式切换(如`syscall`指令) +-----------------------+ | 操作系统内核(内核模式)| → 执行硬操作 +-----------------------+ ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值