Linux内核源码研读与实战演练

滚动学习,坐班辅导
(3人)

295.00 元 5 折

全场5折优惠,咨询QQ810476411

Module signing

.只有签名被匹配的module才会被允许insmod到kernel,用于安全防范

.Enabled by CONFIG_MODULE_SIG

.Introduced in v3.7

 

fedora19->make menuconfig>Enable loadable module support>Module signature verification

 

.相关的编译选项

-CONFIG_MODULE_SIG_FORCE

-CONFIG_MODULE_SIG_ALL

-CONFIG_SIG_SHA1...CONFIG_SIG_SHA512

.手动kernel签名:

scripts/sign-file sha512 kernel-signkey.priv kernel \    -signkey.x509 module.ko

 

fedora19->vim [kernel path].config

 

sysctl

cat /proc/keys

 

Module operations

.lsmod

.insmod

.rmmod

.modprobe

.modinfo

 

VNC

 

fedora19->/lib/modules/3.14.0-rc1+/...

 

[展开全文]
shakyEvil · 2016-10-06 · Module signing 0

实际项目里-可能有上万行代码,有很多的.c文件,有很多.h文件(有我们自己编写的,也有引用第三方提供给我们的库)

dmesg -c > /dev/null (不想让它占据太多屏幕)

 

避免因重复包含所产生的问题-预编译的方式

对于.h 

-> 当前目录#include "other.h"

-> 放在一个目录下

-> 引用第三方库的时候希望简单一点->将第三方的路径加载到当前路径下-kbuild提供的宏-EXTRA_CFLAGS=-I$(shell pwd}/include

 

make M=arch/x86/kvm

modinfo arch/x86/kvm/kvm.ko

module_param(参数(变量名字),参数类型,访问权限)

#standard types:...

#define module_param(name,type,perm)...

 

调用的函数由另外一个模块所提供-和模块的加载顺序有关系

cp ../m1/Module.symvers ./

先加载第一个模块后加载第二个模块

 

[展开全文]

Write a module

-只能使用内核导出的函数,不可使用用户空间的任何lib

-但是并不是kernel的函数你都能使用,只能用下面的符号导出的函数。

。EXPORT_SYMBOL /EXPORT_SYMBOL_GPL

。在.h中实现的函数-所有的实现都要在.h中,如果视线中包含了另外一个函数没有导出的话也是不能用的。

。虽然有这么多限制,但是kernel把一些常用的函数都导出来了。

-初始化与退出函数

。__init/__exit

module_init(minit)-钩子函数,模块加载的时候回去加载这个宏所定义的函数。

module_exit(mexit)-模块卸载的时候被调用

对于一些永远只调用一次的函数,可以用init这样的一个宏来修饰。这个宏会把这个函数所对应的内存放到一个特定的地方,当它被调用完了之后就会把这块内存给free。

-Module License

。MODULE_LICENSE

。如果想要使用GPL导出的函数,也要去声明协议为GPL

-Other module info

。MODULE_AUTHOR

。MODULE_DESCRIPTION

。Others defined in <include/linux/module.h>

。modinfo main.ko

-进阶

。编译有多个源文件的module

。编译多个源文件位于不同目录的module

。指定include.h位置

。模块参数

。编写与编译module之间的依赖

[展开全文]
shakyEvil · 2016-10-06 · Write a module 0

当前module版本和所跑kernel版本不一样->加载内核时提示错误信息

 

-它依赖当前运行内核的编译环境,例如.config, module info, include .h files......

-在发行版上可以安装kernel-devel(on fedora)包

yum search kernel-devel

 

。还可以自行安装一个全新环境

-推荐,因为可以自行修改内核

-下载内核:(使用git能获取所有源码修改信息)

-便于调试,修改源代码再加载内核查看修改效果

.git clone

git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

.load all the modules you need on your box

.make localmodconfig

.make -j6

.make modules modules_install install

.Change your grub and load the new kernel

fedora19

->/boot/grub2/grub.cfg

->做了优化,只要你安装了新内核,就会优先从你的新内核区启动。--如果不是-set default=0

 

git log

git blame [path/filename]

:line_number

git show [commit]

 

linux开发Tree都能在git.kernel.org上找到

 

Write a module Makefile

-指定模块的名字与源文件

.obj-m = <module_name>.o

-编译

.make -C <path_to_kernel_src> M=$PWD

-示例

 

module所编译的语法是由kernel的编译系统所定义的。kernel采用kbuild的系统来编译内核。每一个目录下面有一个kconfig和Makefile

cd /arch/x86/kvm

vi Makefile

vi ~/kvm/.config

 

ls -l /lib/modules/.../build ->对应到当前的kernel的source code

 

Makefile {

obj-m = main.o

all:

    make -C /lib/modules/`uname -r`/build M=`pwd`

clean:

    rm -f *.o *.ko *.mod.c modules.order Module.symvers

}

[展开全文]
shakyEvil · 2016-10-05 · Complie a module 0

模块签名是在3.7内核导入的feature->提高Linux系统安全性,用来防止一些危险的攻击。

 

-本质上module是一段内核代码,它运行在CPU的特权层(Ring 0 on x86),与内核代码具有相同的功能。

-它是kernel的动态扩展,在需要时被加载,在不需要时被移除,可减少内核的footprint

-便于驱动,文件系统等的二次开发。

[展开全文]

kvm.eric@gmail.com

Fedora 19

cat /etc/issue

使用的内核版本跟着KVM版本走

uname -an

 

内核基础

-内核模块

学会内核模块编写之后,就可以写代码验证学到的东西

-上下文介绍

原子环境、中断上下文、可睡眠环境...

-内核同步

内核中锁的使用-主要是信号量、自旋锁;一些原子操作(经常用在...)\内存屏障-优化锁的使用->性能调优

-常用的数据结构

主要是List

[展开全文]

yum kernel-devel

[展开全文]
xmphoenix · 2015-08-16 · Complie a module 0

slob仅适用于嵌入式中(使用资源极少)

[展开全文]
ka1em · 2015-03-22 · 内存映射 续 0

__rcu

rcu

container_of

[展开全文]

======================

中断处理

    普通中断,中断丢失

    softirq 上半部,下半部。上半部快,下半部时间长

网卡工作原理,

[展开全文]

==============

相关编译选项

linux-3.7以上  有模块签名

scripts/sign-file sha512 signing_key.priv \

    signing_key.x509

可以用openssh 生成钥匙 sysctl 加载到内核

=============

[展开全文]
ka1em · 2015-03-14 · Module signing 0

========================

EXPORT_SYMBOL / EXPORT_SYMBOL_GPL

导出函数

=========================

Makefile

obj-m = tmain.o

tmain-y = xxx.o yyy.o

all:

make -C /lib/modules/`uname -r`/build  EXTRA_CFLAGS=-I$(shell pwd)/inlcude M=`pwd`

clean :

rm -f *.o *.ko *.mod.c modules.order Module.symvers

===========================

static int name = 0;

module_param(name, int, S_IRUGO|S_IWUSR);

加载时 insmod tmain.ko name=100

看宏定义module_param 注释

============================

module之间的依赖

第二个模块如果需要第一个模块的函数,那么编译第二个时需要第一个模块的参数表

=============================

[展开全文]
ka1em · 2015-03-14 · Write a module (续) 0

使用EXPORT_SYMBOL、EXPORT_SYMBOL_GPL导出内核函数,模块中才可使用。


[展开全文]
残风 · 2015-03-06 · Write a module 0

Eax = E820 内存

EBX index

ES:DI 用于保存信息buffer

ECX: buffer size

EDX 签名 必须为 “SMAP”


------------------------

返回

CF 调用是否出错

EAX: “SMAP” 不是 表示出错

ES:DI buffer

ECX:BIOS buffer size 

EBX:BIOS 下次调用序号。 0 表示无 所有区间读完


用户空间模拟中断 int


mid 非对称访问


[展开全文]
hypatia2011 · 2015-01-22 · 内存管理 0

page分配器得到的是一个物理页面

page分配器对物理内存的管理

内存地址管理:

kernel的内存映射的方式,CPU寻址时是使用虚拟地址

地址映射:页面映射(段映射基本被废弃了)

TLB是用来缓存从虚拟地址到物理地址映射关系

[展开全文]

内存屏障

内存屏障,简而言之就是强制规定内存访问次序

产生原因:

- 编译器的优化

- CPU的乱序和推测执行


消除编译器导致的乱序

- asm volatile("":::"memory")

- C 语言中的volatile关键字


从x86的内存序谈起

- 相同类型的操作(read vs read; write vs write)不能乱序

A = B = 0

CPU0                    CPU1

write 1 -> A            read B -> R1

write 1 -> B            read A -> R2

不存在 R1 = 1 && R2 = 0

- Write 不到乱序到read前面

A = B = 0

CPU 0                    CPU 1

read A -> R1            read B -> R2

write 1 -> B             write 1 -> A

不存在 R1 = 1 && R2 = 1

- read可能乱序到write前面

A = B = 0

CPU 0                    CPU 1

write 1 -> A            write 1 -> B

read B -> R1          read A -> R2

存在 R1 = 0 && R2 = 0

- CPU内部内存访问允许bypass

A = B = 0

CPU 0                    CPU 1

write 1 -> A            write 1 -> B

read A -> R1           read B -> R3

read B -> R2           read A -> R4

存在 R2 = 0 && R4 = 0

-write 全局可见

A = B = 0

CPU 0                    CPU 1            CPU 2

write 1 -> A           read A ->R1

                            write 1 -> B       read B ->R2

                                                    read A -> R3

不存在 R1 = 1 && R2 = 1 && R3 = 0




[展开全文]
烧仙草 · 2015-01-14 · 内存屏障 0

所谓原子操作,是指不能被cpu和其他cpu所中断的执行指令或指令流


原子操作的实现

CPU基本的原子操作

LOCK前缀

自动带LOCK的指令


CPU平台本身可以保证的原子操作

-读或者写一个字节

-读或者写一个对齐的16-bit数据

-读或者写一个对齐的32-bit数据

-读或者写一个对齐的64-bit数据(64位CPU)

另外:

在32-bit的数据总线上访问一块cache禁止的16位数据(>=Petiunm)

在一个cache line中访问不对其的 16,32,64位数据(>=P6 pamily)


LOCK前缀

-指令前带LOCK前缀迫使CPU做独占的内存访问

-XCHG自动带有LOCK前缀

LOCK在不同CPU版本的实现

-在较老的CPU上,产生LOCK信号以用来锁总线

-在>=P6 family,锁cache line


代码示例:

cmpxchg(ptr.old, new):比较*ptr和old的值,如果相等则*ptr = new.在任何时候该函数返回ptr的初始值.因此,如果想要知道ptr的值是否被New替换,只需要检查其返回值是否与old相等。


自动带LOCK前缀的指令

-xchg

-事物内存(TSX on intel)

可以自定义一块transaction region,然后可以在区域结束的时候原子提交,如果成功提交,则其他CPU可以看到该区域的所有更改,如果提交失败则撤销该区域的所有更改操作,进而转入到程序提供的abort代码。


两种主要的类型

-atomic_t的数据

-bit操作

-其他指令


定义:


atomic_t的操作

-所有的操作都定义在include/linux/atomic.h中以及include/asm/atomic.h中

-常用的atomic操作:

ATOMIC_INIT(i)

atomic_set(v,i)

automic_read(v)

automic_add(i,v)

atomic_sub(i,v)

atomic_inc(v)

atomic_dec(v)

atomic_inc_add_test(v) /*测试新值是否为0*/

atomic_dec_add_test(v)

atomic_xchg(v,new)

atomic_cmpxchg(v,old,new)

atomic_add_negative(i,v) /*测试新值是否为负*/

atomic_add_unless(v,a,u) /*如果v不为u,则v加上a,返回非0,否则直接返回0*/


bit操作

-原子性的位操作

-常用的原子位操作

set_bit(nr, *addr)

clear_bit(nr, *addr)

test_bit(nr, *addr)

change_bit(nr, *addr)

test_and_set_bit(nr, addr) /*测试旧位是否已经设置*/

test_and_clear_bit(nr, *addr)

test_and_change_bit(nr, *addr)

-另外,非原子的位操作

__set_bit(nr, *addr)

__clear_bit(nr, *addr)

test_bit(nr, *addr)

__change_bit(nr, *addr)

__test_and_set_bit(nr, addr) /*测试旧位是否已经设置*/


其他指令(包含原子)

- xchg()

- cmpxchg()

- cmpxchg_double()


[展开全文]
烧仙草 · 2015-01-10 · 原子操作 0

内核中不被使用的函数,编译时会被忽略掉

lwn.net

[展开全文]

SRCU(sleepable RCU)

使用

初始化:

1)编译时初始化DEFINE_SRCU()/DEFINE_STATIC_SRCU()

2)运行时初始化 init_srcu_struct()

读者:

获得锁 srcu_read_lock()

获得保护的指针 srcu_dereference()

释放锁 srcu_read_unlock()

写者释放旧指针 synchronize_srcu()/call_srcu()

使用完成后 cleanup_srcu_struct()


[展开全文]

completion

completion用于显式地等待一个事件

初始化

编译时初始化 DECLARE_COMPLETION()

运行时初始化 init_completion()

等待事件

wait_for_completion()/wait_for_completion_interruptible()/wait_for_completion_killable()/wait_for_completion_io()/wait_for_completion_xxx_timeout

事情完成

Complete()/complete_all()

complete()只会唤醒一个正在等待的进程而complete_all()则唤醒

[展开全文]

授课老师

Linux内核华人贡献前10

学员动态

麦兜帽子 开始学习课时 上下文:抢占
JoeyZhang928 开始学习课时 内存管理
JoeyZhang928 开始学习课时 第一周课程介绍
曹卫锋 开始学习课时 中断/异常处理
山鹰 开始学习课时 第一周答疑视频

QQ客服: 810476411

QQ咨询: 810476411

QQ吐槽: 810476411

服务时间: 9:00 - 21:00

刘老师: 18516031455

微信公众号:开源力量