郭垚 原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
1. 通过库函数完成系统调用:库函数将系统调用封装起来。
2. 用户态与内核态
3. 区分用户态与内核态的方法
(主要是通过代码段选择寄存器cs和偏移量寄存器eip)
(上述两个判断由硬件完成)
注:逻辑地址是进程的地址空间中的。
4. 中断处理
5. 保护现场与恢复现场
保护现场:进入中断程序,保存需要用到的寄存器的数据(中断发生后的第一件事)
#define SAVE_ALL //将其他寄存器的值push到内核堆栈中
恢复现场:退出中断程序,恢复保存寄存器的数据(中断处理结束前最后一件事)
#RESTORE_ALL //将用户态保存的寄存器pop到当前CPU中
iret指令:iret指令与中断信号(包括int指令)发生时的CPU的动作相反
6. 中断处理的完整过程
第一步
interrupt(ex:int 0x80)-save //int 0x80指系统调用
cs:eip/ss:esp/eflags(current)to kernel stack,then //中断将cs:eip、ss:esp(当前堆栈段栈顶)、eflags(当前标志寄存器)保存到内核堆栈中
load cs:eip(entry of a specific ISR)and //将当前中断信号相关联的中断服务入口加载到cs:eip
ss:esp(point to kernel stack). //同时将当前指向内核信息的的堆栈段和esp也加载到CPU中
第二步
SAVE_ALL
-... //内核代码,完成中断服务,(完成中断服务后可能)发生进程调度
//如果发生了进程调度,则当前的状态都会暂时保存在系统中。当其他进程调度切换回当前进程时,则接着执行RESTORE_ALL
第三步
RESTORE_ALL
第四步
iret -pop cs:eip/ss:esp/eflags from kernel stack
1. 系统调用概述
系统调用是操作系统为用户态进程与硬件设备进行交互提供的一组接口。
2. API和系统调用

用户态<->内核态
3. 系统调用的三层皮
系统调用的三层皮:xyz(API)、system_ call(中断向量)、sys_xyz(中断向量对应的中断服务程序)
4. 系统调用程序及服务例程
5. 参数传递
C代码time.c :
#include <stdio.h>
#include <time.h>
int main()
{
time_t tt;//int型数值
struct tm *t; //便于输出值可读
tt = time(NULL);
t = localtime(&tt);//将tt转换成之前声明的t类型,便于可读
printf("time:%d:%d:%d:%d:%d:%d:\n",t->tm_year+1960,t->tm_mon,t->tm_mda,t->tm_hour,t->tm_min,t->tm_sec);
return 0;
}
详细语法见http://www.cnblogs.com/20135228guoyao/p/5243214.html
嵌入汇编代码time_asm.c :
#include <stdio.h>
#include <time.h>
int main()
{
time_t tt;//int型数值
struct tm *t;
asm volatile(
"mov $0,%%ebx\n\t"//系统调用传递第一个参数使用ebx,这里是null
"mov $0xd,%%eax\n\t"//使用%eax传递系统调用号13,用16进制表示为0xd
"int $0x80\n\t" //执行系统调用
"mov %%eax,%0\n\t"//通过eax这个寄存器返回系统调用值,和普通函数一样
:"=m"(tt)
);
t = localtime(&tt);
printf("time:%d:%d:%d:%d:%d:%d:\n",t->tm_year+1960,t->tm_mon,t->tm_mda,t->tm_hour,t->tm_min,t->tm_sec);
return 0;
}
使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用。本次实验中我使用第20号系统调用getpid()函数,用于取得进程识别码。
C代码(getpid.c):
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
pid = getpid();
printf("pid = %d \n",pid);
return 0;
}

嵌入汇编代码getpid_asm.c:
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
pid = getpid();
asm volatile(
"mov $0,%%ebx\n\t" //系统调用传递第一个参数使用ebx,因为这里没有传入参数所以是null
"mov $0x14,%%eax\n\t" //使用%eax传递系统调用号20,用16进制表示为0x14
"int $0x80\n\t" //执行系统调用
"mov %%eax,%0\n\t" //将%0(即pid的返回值)放到%eax寄存器中
: "=m" (pid)
);
printf("pid = %d \n",pid);
return 0;
}

系统调用是操作系统为用户态进程与硬件设备进行交互提供的一组接口,也是一种特殊的中断,可使用户态切换到内核态。当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。同时我通过实践掌握了用户态进程切换到内核态的具体过程:使用ebx传递系统调用第一个参数、使用eax传递系统调用号、int $0x80指令执行系统调用、最后将返回值存入eax。
原文:http://www.cnblogs.com/20135228guoyao/p/5284262.html