2008年9月25日星期四

LKD 笔记 3

第 5 章 系统调用
为了和用户空间运行的程序进行交互,内核提供的一组接口.
系统调用在用户空间进程和硬件设备之间添加了一个中间层, 有以下三个作用
1. 为用户空间提供一个硬件抽象接口
2. 保证系统的稳定和安全. 可以避免应用程序不正确的使用硬件设备等造成对系统的危害.
3. 对每个进程虚拟空间实现的支持

在linux中系统调用是用户空间访问内核的唯一手段. 除异常和陷入外,它们是内核唯一的合法入口.

linux系统调用作为c库的一部分提供,并且c库提供了POSIX的绝大部分API.

提供机制而不是策略

asmlinkage 用于通知编译器仅从栈中提取该函数的参数.
所有系统调用都需要这个限定词.
所有系统调用在内核的实现都带sys_

系统调用号与系统调用进行对应,当用户程序执行一个系统调用的时候, 系统调用号被用来指明到底要调用哪个系统调用
进程不会提及系统调用的名称

linux有一个"未实现"系统调用 sys_ni_syscall() 返回-ENOSYS 它是针对无效系统调用设置的

内核记录了系统调用表中的所有已经注册的系统调用列表,存储在sys_call_table中, 这个表中为每一个有效的系统调用指定了
唯一的系统调用号.

系统调用处理程序system_call()
用户进程通过软中断通知内核,软中断导致系统切换到内核态并执行第128号异常处理程序,即系统调用处理程序.

调用系统调用的时候,eax用来放置相应的系统调用号
参数传递通过ebx ecx edx esi edi来放置前5个参数, 给用户空间的返回值也通过寄存器传递

系统调用的实现

"提供机制而不是策略"

参数验证
系统调用必须仔细检查他们的参数是否合法有效.
指针检查:
1. 指针指向的内存区域属于用户空间
2. 指针指向的区域在进程的地址空间里
3. 进程不能绕过内存访问限制进行内存操作

copy_to_user() copy_from_user() 执行失败 返回没能完成拷贝的字节数, 否则返回0

保证系统调用可重入 reentrant

sys_call_table asm/unistd.h

第 6 章 中断和中断处理程序
中断机制: 让硬件在需要时再向内核发出信号.

在响应一个特定中断的时候,内核会执行一个函数 即中断处理程序
中断处理程序是和特定的中断关联的
中断处理程序运行于中断上下文
中断处理程序分上半部与下半部
上半部只做有严格时限的工作,例如对接收的中断进行应答
那些允许可以稍侯完成的工作被放到下半部

drivers can register and active a interrupt handler by the following function
int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void*, struct pt_regs *),
unsigned long irqflags, const char *devname, void* dev_id)

irqflags:
SA_INTERRUPT: fast interrupt handler. 在本地处理器上,中断处理程序在禁止所有中断的情况下运行.
SA_SAMPLE_RANDOM:
SA_SHIRQ: 多个中断处理程序共享中断线

release handler
void free_irq(unsigned int irq, void *dev_id);

一个典型的中断处理程序声明
static irqreturn_t intr_handler(int irq, void* dev_id, struct pt_regs* regs);

linux 的中断处理程序是无需重入的
当一个给定的中断处理程序正在执行的时候,相应的中断线在所有的处理器上都会被屏蔽

共享的中断处理程序

与非共享的差异:
1. irqflags必须为SA_SHIRQ
2. 对每个注册的中断处理程序来说, dev_id必须唯一. 不能传递NULL
3. 中断处理程序必须能够区分它的设备是否真的产生了中断. 必须硬件支持,同时中断处理程序有相应的处理逻辑

当执行一个中断处理程序或下半部的时候, 内核处于中断上下文

local_irq_disable()
local_irq_enable()
禁止和允许当前处理器上的中断
unsigned long flag;
local_irq_save(flag)
local_irq_restore(flag)

禁止指定中断线
void disable_irq(unsigned int irq);
void disable_irq_nosync(unsigned int irq);
void enable_irq(unsigned int irq);
void synchronize_irq(unsigned int irq);

对disable_irq()和disable_irq_nosync()的每次调用都需要相应的调用一个enable_irq()
in_interrupt() 在中断上下文返回非0, 进程上下文返回0
in_irq() 正在执行中断处理程序返回非0

没有评论: