一、内核
操作系统是一系列程序的集合,其中最重要的部分构成了内核
单内核/微内核
单内核是一个很大的进程,内部可以分为若干模块,运行时是一个独立的二进制文件,模块间通讯通过直接调用函数实现
微内核中大部分内核作为独立的进程在特权下运行,通过消息传递进行通讯
Linux内核的能力
内存管理,文件系统,进程管理,多线程支持,抢占式,多处理支持
Linux内核区别于其他UNIX商业内核的优点
单内核,模块支持
免费/开源
支持多种CPU,硬件支持能力非常强大
Linux开发者都是非常出色的程序员
通过学习Linux内核的源码可以了解现代操作系统的实现原理
层次结构
二、模块&驱动
许多常见驱动的源代码集成在内核源码里
也有第三方开发的驱动,可以单独编译成 模块.ko
insmod
rmmod
2)高层命令
modprobe
modprobe -r
内核编程和外围程序的差别。(主观题,要能写出一段) 重点!
内核编程的注意点
不能使用C库来开发驱动程序
没有内存保护机制
小内核栈
并发上的考虑
4.
内核模块的一个简单例子(要能看懂)
#include <linux/module.h>
#include <linux/init.h>
static int __init hello_init(void)
{
printk(KERN_INFO "Hello world\n");
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "Goodbye world\n");
}
module_init(hello_init);
module_exit(hello_exit);
• static int __init hello_init(void)
• static void __exit hello_exit(void)
– Static声明,因为这种函数在特定文件之外没有其它意义
– __init标记, 该函数只在初始化期间使用。模块装载后,将
该函数占用的内存空间释放
– __exit标记 该代码仅用于模块卸载。
• Init/exit
– 宏:module_init/module_exit
– 声明模块初始化及清除函数所在的位置
– 装载和卸载模块时,内核可以自动找到相应的函数
module_init(hello_init);
module_exit(hello_exit);
驱动的代码要求能看懂
模块参数的传递
7. /proc和/dev
在linux的根目录下有一个/proc目录,/proc文件系统是一个虚拟文件系统,通过它可以使用一种新的方法在Linux内核空间和用户空间之间进行通信。在/proc文件系统中,我们可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段,但是与普通文件不同的是,这些虚拟文件的内容都是动态创建的(即在我们执行指令的那一刹那才产生的)
/proc文件系统包含了:
设备文件分为两种: 块设备文件(b)和字符设备文件(c),对于/dev我们需要明白,它不是设备驱动,linux有自己的设备驱动,/dev下的文件只是访问相应驱动的接口
设备文件一般存放在/dev目录下,对常见设备文件作如下说明:
• 字符设备 Character Driver
• 块设备 Block Driver
• 网络接口设备 Network Driver
常见要开发的有:触摸屏,自定义键盘,视频捕捉设备,音频设备等
块设备Block device:采用数据块方式访问的设备,如磁盘等,可以随意移动访问。和字符设备的差异在于内核内部管理数据的方式,如采用缓存机制等。并必须支持 mount文件系统。基本上不用自己开发,象硬盘,光盘,USB存储设备等Linux都提供了
网络接口 network interface(需要自己开发):数据包传输方式访问的设备,和上两者不同。通过ifconfig来创建和配置设备。网络驱动同块驱动最大的不同在于网络驱动异步接受外界数据,而块驱动只对内核的请求作出响应
其他:总线类,如USB, PCI, SCSI等,一般同其他驱动联合使用
常见要开发的如采用IIC,SPI,USB通信的一些设备驱动。
• 主设备号和次设备号统称为设备号。主设备号用来表示一个特定的驱动程序。
• 次设备号用来表示使用该驱动程序的各设备。
• 定义文件操作结构体 file_operations
• 创建并初始化定义结构体 cdev
• 将cdev注册到系统,并和对应的设备号绑定
• 在/dev文件系统中用mknod创建设备文件,并将该文件绑定到设备号上
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
...
};
struct file {
/*
* fu_list becomes invalid after file_free is called and queued via
* fu_rcuhead for RCU freeing
*/
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;
atomic_t f_count;
unsigned int f_flags;
mode_t f_mode;
loff_t f_pos;
struct fown_struct f_owner;
unsigned int f_uid, f_gid;
struct file_ra_state f_ra;
unsigned long f_version;
#ifdef CONFIG_SECURITY
void *f_security;
#endif
/* needed for tty driver, and maybe others */
void *private_data;
#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
spinlock_t f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
};
内核模块的一个简单例子(要能看懂)
内核模块的一个简单例子(要能看懂)