
内核模块:内核模块就是被单独编译的一段内核代码,它可以在需要的时候动态地加载到内核,从而动态地增加内核的功能。在不需要的时候可以动态地卸载,从而减少内核的功能,并节约一部分内存(这要求内核配置了模块可卸载选项才行)
#include#include #include int init_module(void) { printk("module initn"); return 0; } void cleanup_module(void) { printfk("cleanup modulen"); }
#include2.6内核模块依赖#include #include static int_init vser_init(void) { printk("vser_initn"); return 0; } static void_exit vser_exit(void) { printk("vser_exitn"); } module_init(vser_init); module_exit(vser_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kevin Jiang "); MODULE_DESCRIPTION("A simple module"); MODULE_ALIAS("virtual-serial");
#include#include #include extern int expval; extern void expfun(void); static int _init vser_init(void) { printk("vser_initn"); printk("expval: %dn",expval); expfun(); return 0; } static void _exit vser_exit(void) { printk("vser_exitn"); } module_init(vser_init); module_exit(vser_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kevin Jiang "); MODULE_DESCRIPTION("A simple module"); MODULE_ALIAS("virtual-serial");
#include#include static int expval = 5; EXPORT_SYMBOL(expval); static void expfun(void) { printk("expfun"); } EXPORT_SYMBOL_GPL(expfun); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kevin Jiang ")
在默认情况下,模块初始化函数的名字是(A),模块清除函数是(B)
A init_module B.cleanup_module C.mod_init D.mod_exit
加载模块可以用哪个命令(A、D)
A.insmod B.rmmod C.depmod D.modprobe
查看模块信息可以用哪个命令(C)
A.insmod B.rrmod C.modinfo D.modprobe
内核模块参数的类型不包括(D)
A.布尔 B.字符串指针 C.数组 D.结构
内核模块导出用哪个宏(C)
A.MODULE_EXPROT B.MODULE_PARAM C.EXPORT_SYMBOL D.MODULE_LICENSE
内核模块能否能调用C库的函数(B)
A.能 B.不能
在内核模块的代码中,我们能否定义任意大小的局部变量(B)
A.能 B.不能
#include#include #include #include #define VSER_MAJOR 256 #define VSER_MINOR 0 #define VSER_DEV_CNT 1 #defnie VSER_DEV_NAME "vser" static int _init vser_init(void) { int ret; dev_t dev; dev = MKDEV(VSER_MAJOR,VSER_MINOR); ret = register_chrdev_region(dev,VSER_DEV_CNT,VSER_DEV_NAME); if(ret) goto reg_err; return 0; reg_err: return ret; } static void_exit vser_exit(void) { dev_t dev; dev = MKDEV(VSER_MAJOR,VSER_MINOR); unregister_chrdev_region(dev,VSER_DEV_CNT); } module_init(vser_init); module_exit(vser_exit); MODULE_LICENST("GPL"); MODULE_AUTHOR("Kevin Jiang "); MODULE_DESCRIPTION("A simple character device driver"); MODULE_ALIAS("virtual-serial");
使用MKDEV宏将主设备号和次设备号合成一个设备号。在当前内核版本中dev_t是一个无符号的32位整数,很自然的,主设备号占12位,次设备号占20位。另外还有两个宏为****MAJOR和MINOR,它们分别是从设备号中取出的主设备号和次设备号的两个宏。
cdev_init的函数原型如下,第一个参数是要初始化的cdev地址,第二个参数是设备操作方法集合的结构地址。
void cdev_init(struct cdev*cdev, const struct file_operations *fops);
3.3虚拟串口设备int cdev_add(struct cdev *p, dev_t dev, unsigned count);
DEFINE_KFIFO(fifo, type, size)
kfifo_from_user(fifo, from, len, copied)
kfifo_to_user(fifo, to, len, copid)
字符设备和块设备的区别不包括(C)
A.字符设备按字节流进行访问,块设备按块大小进行访问
B.字符设备智能处理可打印字符,块设备可以处理二进制数据
C.多数字符设备不能随机访问,而块设备一定能随机访问
D.字符设备通常没有页高速缓存,而块设备有
在3.14.25版本的内核中,主设备号占(C)位,次次设备号占(D)位
A.8 B.16 C.12 D.20
用于分配主次设备号的函数是(C)
A.register_chrdev_region B.MKDEV C.alloc_chrdev_region D.MAJOR
在字符设备驱动中,struct file_operations结构中的函数指针成员不包括(B)
A.open B.close C.read D.show_fdinfo
比特位 含义 31-30 00 - 命令不带参数 10 - 命令需要从驱动中获取数据,读方向 01 - 命令需要把数据写入驱动,写方向 11 - 命令既需要写入数据又要获取数据,读写方向 29-16 如果命令带参数,则指定参数所占用的内存空间大小 15-8 每个驱动全局唯一的幻数(魔术) 7-0 命令码
unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n); unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n);4.4阻塞型I/O
这里以poll为例来进行说明,poll系统调用的原型及相关的数据结构类型如下:
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd{
int fd;
short events;
short revents;
};
POLLIN There is data to read.
POLLOUT Writting now will not block.
POLLRDNORM Equivalent to POLLIN.
POLLWRNORM Equivalent to POLLOUT.
中断处理函数原型如下
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);
flags:与中断相关的标志,用于初始化struct irqaction对象中的flags成员,常用的标志如下,这些标志可以用位或的方式来设置多个
关于中断使能和禁止的函数或宏,这些函数罗列如下:
靠循环来延时的宏或函数:
void ndelay(unsigned long x); udelay(n) mdelay(n)
如果延时时间较长,有没有特殊要求,那么可以使用休眠延时
void msleep(unsigned int msecs); long msleep_interruptible(unsigned int msecs); void ssleep(unsigned int second);
关于中断处理例程说法错误的是(C)
A.需要尽快完成
B.不能调用可能会引起进程休眠的函数
C.如果中断时共享的,内核会决定具体调用哪一个驱动的中断服务例程
D.工作在中断上下文
中断的下半部机制包括(A、B、C)
A.软中断 B.tasklet C.工作队列
关于软中断下半部机制的说法正确的是(B)
A.可以使处理的总时间减少
B.可以提高CPU的利用率
C.每种下半部机制都不运行在中断上下文中
D.在下半部中可以响应新的硬件中断
下面哪种下半部机制工作在进程上下文中(C)
A.软中断 B.tasklet C.工作队列
修改低分辨率定时器的expires成员使用(C)函数
A.init_timer B.add_timer C.mod_timer D.del_timer
关于低分辨率定时器说法错误的是(D)
A.分辨率受HZ的影响
B.function函数指针指向的函数运行在中断上下文中
C.使用mod_timer可以实现循环定时
D.所有定时器都放在一个组中,遍历整个链表非常耗时
高分辨率定时器是用(C)来定义时间的
A.HZ B.jiffies C.ktime_t
内核中的并发情况有(A、B、C、D、E)
A.硬件中断 B.软中断和tasklet C.抢占内核的多进程环境 D.普通的多进程环境
E.多处理器或多核CPU
local_irq_save的作用是(C)
A.禁止全局中断 B.禁止本CPU中断 C.禁止本CPU中断并将之前的中断使能状态保存下来
可以对原子变量进行的操作有(A、B、C、D)
A.自减并测试结果是否为0 B.加上一个整数值并返回结果
C.进行位清除 D.变量中指定的比特位交换
关于自旋锁的使用说法错误的是(C)
A.获得自旋锁的临界代码不宜过长
B.在获得锁的期间不能够调用可能会引起进程切换的函数
C.自旋锁可以用于中断上下文中
D.在所有系统中,即不管是否抢占、是否多核,自旋锁都是忙等锁。
关于信号量的使用说法错误的是(D)
A.如果不能获得信号量,则进程休眠
B.在中断上下文不能调用down函数来获取信号量
C.在获得信号量期间,进程可以休眠
D.相比于自旋锁,优先使用信号量
关于RCU说法错误的是(A)
A.写者完成写后立即更新指针
B.适合于读访问多、写访问少的情况
C.对共享资源的访问都是通过指针来实现的
D.尽可能地减少了对锁地使用
完成量地complete函数可以唤醒(A)进程
A.一个 B.所有
page_address:只用于非高端内存地虚拟地址的获取。
kmap:用于返回分配地高端或非高端内存地虚拟地址,如果不是高端内存,则内部调用地其实是page_address,也叫永久映射。
kmap_atomic:和kmap功能类似,但操作时原子性地,也叫作临时映射。
kunmap:用于解除前面的映射。
void *vmalloc(unsigned long size); void *vzalloc(unsigned long size); void vfree(const void *addr);7.7I/O内存
Linux地内存区域有(A、B、C)
A.ZONE_DMA B.ZONE_NORMAL C.ZONE_HIGHMEM
alloc_page函数地order参数表示(B)
A.分配地页数为order
B.分配地页数为2地order次方
如果指定了__GFP_HIGHMEM,表示可以在那些区域分配内存(C)
A.ZONE_DMA B.ZONE_NORMAL C.CONE_HIGHMEM
用于永久映射地函数是(A)
A.kamp B.kamp_atomic
用于临时映射地函数是(B)
A.kamp B.kamp_atomic
在内核中如果要分配128个字节,使用下面哪个函数比较合适(D)
A.alloc_page B.__get_free_pages
C.malloc D.kmalloc
能分配大块内存,但物理地址不一定连续地函数是(A)
A.vmalloc B.__get_free_pages C.malloc D.kmalloc
per-CPU变量指的是(A)
A.每一个CPU有一个变量地副本
B.多个CPU公用一个变量
映射I/O内存地函数是(B)
A.kmap B.ioremap
平台驱动是用struct platform_driver结构来表示de
A.kamp B.kamp_atomic
在内核中如果要分配128个字节,使用下面哪个函数比较合适(D)
A.alloc_page B.__get_free_pages
C.malloc D.kmalloc
能分配大块内存,但物理地址不一定连续地函数是(A)
A.vmalloc B.__get_free_pages C.malloc D.kmalloc
per-CPU变量指的是(A)
A.每一个CPU有一个变量地副本
B.多个CPU公用一个变量
映射I/O内存地函数是(B)
A.kmap B.ioremap