Chinaunix首页 | 论坛 | 博客
  • 博客访问: 829059
  • 博文数量: 281
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2770
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-02 19:45
个人简介

邮箱:zhuimengcanyang@163.com 痴爱嵌入式技术的蜗牛

文章分类
文章存档

2020年(1)

2018年(1)

2017年(56)

2016年(72)

2015年(151)

分类: 嵌入式

2015-06-25 12:59:33

接上一篇。

③核心模块和应用程序的对比

编译链接方式:
应用程序可以调用它并未定义的函数,这是因为连接过程能够解析外部引用从而使用适当的函数库。比如,定义在libc中的printf函数就是这种可被调用的函数之一。
模块仅仅被连接到内核,因此它能调用的函数仅仅是由内核导出的那些函数,而不存在任何可链接的函数库。printk函数就是由内核定义并导出给模块使用的一个printf的内核版本。

因为没有任何函数库会和模块链接,因此,源文件中不能包含通常的头文件。
内核模块只能使用作为内核一部分的函数。和内核相关的任何内容都在我们安装并配置好的内核源码树的头文件中声明。
其中,大多数相关头文件保存在include/linux和include/asm目录中,但include的其他子目录保存有和特定内核子系统相关的头文件。

处理错误的方式:
a. 应用程序开发过程中的段错误是无害的,并且总是可以使用调试器追踪到源代码中的问题所在。
b. 内核错误即使不影响系统,也至少会杀死当前进程。

3.1 用户空间和内核空间

模块运行在内核空间,应用程序运行在用户空间中,这是操作系统理论的基础之一。
操作系统的作用是为应用程序提供一个对计算机硬件的一致视图。更重要一点:操作系统必须负责程序的独立操作并保护资源不受非法访问。

现代处理器具有不同的运行级别。内核运行在最高级别(超级用户态),而应用程序运行在最低级别(用户态
我们通常将运行模式称为内核空间和用户空间,这两种模式具有不同的优先权等级,具有各自的内存映射,也即自己的地址空间。

当应用程序执行系统调用(比如执行open,read,write函数)或者硬件中断挂起时,Unix将执行模式从用户空间切换到内核空间。
执行系统调用的内核代码运行在进程上下文中,它代表调用进程执行的操作,因此能够访问进程地址空间的所有数据。
而处理硬件中断的内核代码和进程是异步的,与任何一个特定进程无关。

模块化代码(也即驱动程序)在内核空间运行,用于扩展内核的功能。
一个驱动程序要执行两类任务:
a. 模块中的某些函数作为系统调用的一部分执行;
b. 模块中的其他函数则负责中断处理。

3.2 内核中的并发

内核编程必须考虑并发问题,这是区别于应用程序编程的地方。
大部分应用程序,除了多线程应用程序以外,通常都是顺序执行的。

内核编程需要考虑并发问题的原因:
a. Linux系统通常正在运行多个并发进程,并且可能多个进程同时使用驱动程序;
b. 大多数设备能够中断处理器,而中断处理程序异步执行,而且可能在驱动程序正试图处理其他任务时被调用;
c. 一些软件抽象(比如内核定时器)也在异步运行;
d. Linux还可能运行在SMP系统上;
e. 在2.6中的内核代码是可以抢占的。

并发问题使得:
Linux内核代码,包括驱动代码,必须是可重入的,它必须能够同时运行在多个上下文中。
对于编写正确的内核代码来说,优良的并发管理是必须的。

3.3 当前进程

3.4 其他一些细节


④编译和装载

关于Makefile,编译的工作可以查看资料。这里先不介绍了。


版本依赖

有一段话很重要:

“内核不会假定一个给定的模块是针对正确的内核版本构造的。在我们构造过程中,可以将自己的模块和当前内核树中的一个文件(即vermagic.o)链接;该目标文件包含了大量有关内核的信息,包括目标内核版本、编译器版本以及一些重要配置变量的设置。在试图装载模块时,这些信息可用来检查模块和正在运行的内核的兼容性。如果有任何不匹配,就不会装载该模块,同时可以看到如下信息:
#insmod hello.ko
Error inserting './hello.ko': -1 Invalid module format

这段话告诉我们:在某个版本的内核树下编译的驱动模块,只能加载运行在相同内核版本的系统下面。







阅读(801) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~