linux 驱动学习笔记

最近有想深入驱动和内核的想法,所以开始学习ldd3,参考着写一篇学习笔记

背景知识

什么是驱动

驱动在Linux内核中担任着特殊的角色,像是一个黑箱,隐藏掉设备工作的具体细节,并且具有模块化的特点,可以和内核的其他部分分开编译,并且可以随时装载卸载。

the role of a device driver is providing mechanism, not policy

mechanism指的是提供什么样的方法,policy指的是这些方法可以怎样使用,将这两个问题分开解决,用程序不同的部分甚至是不同的程序去实现,可以使开发变得更简单。

书中举了一个很简单的例子可以帮助很好的理解,Linux图形界面显示就可以分为两部分,一部分是X Server用以驱动显卡并给替它程序提供接口,另一部分就是我们比较熟悉的窗口管理器(比如我现在用的gnome-session),在之前安装arch linux的时候有很深的体会。

When writing drivers, a programmer should pay particular attention to this fundamental concept: write kernel code to access the hardware, but don’t force particular policies on the user, since different users have different needs.

这句话很关键,驱动程序只需要提供调用硬件的接口就可以了,并且越是policy free就越有利于实现应用可以在不同的环境下运行

内核浅析

在Unix系统中,进程会请求很多系统资源,比如cpu算力,内存,网络或者是其他资源,内核,简单来说,就是一堆可执行的代码,负责管理这些请求。内核大致可以分为以下几个部分:

  • 进程管理

    管理创建和销毁进程,进程之间的通信或者是cpu的分配

  • 内存管理

    内存管理其负责为程序分配虚拟内存

  • 文件系统

    以前看过这样一句话,几乎Unix系统中的一切都可以当作文件来看

  • 设备控制

    提供驱动管理,就是目前学习的重点

  • 网络

模块化

Each piece of code that can be added to the kernel at runtime is called a module.

模块可以通过insmod装载并且可以通过rmmod卸载

模块也有很多种类,但分类的方式并不绝对,本书中分为了三类

  • a char module
  • a block module
  • a network module

内核中的各种功能,无论是硬件还是软件,都是模块化的

安全问题

如果内核存在安全漏洞,整个系统就是不安全的。系统通过调用init_module来检测用户是否有权限,也只有有权限的用户才可以装载模块

从hello world开始

第一个程序惯例从hello world开始,先写一个很简单的程序,即使没有任何内核基础也能看出大概意思来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//hello.c
#include<linux/init.h>
#include<linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void){
printk(KERN_ALERT"Hello,world\n");
return 0;
}

static void hello_exit(void){
printk(KERN_ALERT"Goodbye,cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);

这个模块定义了两个函数,一个在模块载入(通过module_init加载)的时候调用,一个在模块卸载(通过module_exit加载)的时候调用,module_initmodule_exit是指定函数作用的两个宏定义。另外一个宏定义就是MODULE_LICENSE,这里用来指定的是free license,没有license的模块在装载的时候会因为安全问题被禁用,导致装载失败。

printk顾名思义就是打印,很像printf,但是是打印在log里,可以使用dmesg命令查看。

注意在make的之前要先安装linux-header,我的环境是kali,使用的命令时是

1
sudo apt-get install linux-headers-$(uname -r)

Makefile如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ifeq ($(KERNELRELEASE),)

# Assume the source tree is where the running kernel was built
# You should set KERNELDIR in the environment if it's elsewhere
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
# The current directory is passed to sub-makes as argument
PWD := $(shell pwd)

modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module.symvers modules.order

.PHONY: modules modules_install clean

else
# called from kernel build system: just declare what our modules are
obj-m := hello.o
endif

make成功之后使用sudo insmod hello.ko加载模块,使用sudo rmmod hello.ko卸载模块,之后可以使用sudo dmesg查看打印出来的信息

hello

攻防世界_Crypto_wp WPICTF-re-wp

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×