EDA365电子论坛网
标题:
Linux内核设计与实现之内核开发的准备
[打印本页]
作者:
pulbieup
时间:
2020-9-24 15:17
标题:
Linux内核设计与实现之内核开发的准备
- Y' w* C# t0 b5 z: F
在尝试内核开发之前,需要对内核有个整体的了解。
+ |% r" j- z! S- k
4 m; k9 g* [: k. p% Y
主要内容:
( V. `; E7 o3 U0 k) m4 M1 [: |
4 l9 S+ ~; ~& i- s
获取内核源码
$ D1 {, N x% X7 h7 s! x3 V
内核源码的结构
$ j! B+ i$ k6 s2 E& ?* \
编译内核的方法
4 x0 g0 o8 g) \( Y5 R: F; W
内核开发的特点
* d& C& J& |; U3 |$ f
, \ v! I8 }+ g6 o
' r* Q- t% s9 g! l' W' |' j- t. c
1. 获取内核源码
( J _/ o @/ _& ~& z/ {
内核是开源的,所有获取源码特别方便,参照以下的网址,可以通过git或者直接下载压缩好的源码包。
. @9 o+ V$ I6 V" y$ E$ Z' {
# \; F& \' u1 k8 F: N
http://www.kernel.org
_, }3 D( \1 Q
T0 x" k; l( d C. @4 H& w4 X
8 t' X5 {7 G) }& I) i
3 N# A% m/ J. v
2. 内核源码的结构
8 ^" m) L1 N* f$ u" w/ Y5 L$ A! f
- q D( [2 I8 M' w9 J
# g$ M3 f& j9 h7 L$ L
目录 说明
" l: \- W' t2 Y( i) b
arch 特定体系结构的代码
4 X7 ^# Q: w9 ~
block 块设备I/O层
, C1 Q% ^7 J# |4 k! D8 L
crypo 加密API
9 t; E! K% z4 d, ^/ G
Documentation 内核源码文档
, o, S# x* a6 r# P7 M. y: {
drivers 设备驱动程序
' l) J* D6 s$ C$ {: }
firmware 使用某些驱动程序而需要的设备固件
* S* x: J# E$ h; v, J$ \0 Q; F
fs VFS和各种文件系统
4 d. e6 p2 [# }; D, ^$ f1 A" C/ p
include 内核头文件
% y! N8 \5 F# g3 N
init 内核引导和初始化
. l' D$ d, G: I& t; n2 ~/ V
ipc 进程间通信代码
; v6 T+ z4 Q- Q1 S* r4 K% A
kernel 像调度程序这样的核心子系统
; _6 Y9 ]6 x' r( q) R4 W/ h
lib 同样内核函数
) }+ A8 i6 @2 c0 i- q$ [
mm 内存管理子系统和VM
) a' ~2 h& w! |) [ v
net 网络子系统
0 ]: P( j% h. _, |% z3 f8 k v9 B% x
samples 示例,示范代码
6 ], t' k' G; N- c3 d. @
scripts 编译内核所用的脚本
2 ?0 [8 X X4 d
security Linux 安全模块
8 K5 ~8 I' T. S2 F; i7 a
sound 语音子系统
/ C: [" q0 T7 i1 s+ n. P+ H
usr 早期用户空间代码(所谓的initramfs)
5 e+ `: @9 F* \6 L" G
tools 在Linux开发中有用的工具
; b5 _2 T8 H5 h* f; V2 S% t+ M
virt 虚拟化基础结构
3 D: o; z9 x$ k* t4 t4 [
# m8 z1 o" L' G r. L* s
* E# _$ n' y+ {% F0 ~
3. 编译内核的方法
5 w" }# V5 C- Y W1 w# [4 g
还未实际尝试过手动编译内核,只是用yum更新过内核。这部分等以后手动编译过再补上。
# l4 \# i; R3 [ p- N5 }3 e- w
, O6 b [! {$ e! L2 `
安装新的内核后,重启时会提示进入哪个内核。当多次安装新的内核后,启动列表会很长(因为有很多版本的内核),显得不是很方便。
+ y: S; k8 s+ D; ^2 a6 d
+ G" ?% N, E+ k2 H
下面介绍3种删除那些不用的内核的方法:(是如何安装的就选择相应的删除方法)
8 F- h5 X( ^) W1 [/ G
8 w$ o$ N2 _+ P- {
3.1 rpm 删除法
z9 w- O: ]$ i- L( {# O7 o
rpm -qa | grep kernel* (查找所有linux内核版本)
9 ]8 m$ @5 D. c+ F: L3 w4 N
rpm -e kernel-(想要删除的版本)
# V% H; O2 x o# q# ?- ^; S: v: W
' ~% u: `7 H! b/ S6 g7 l7 q
3.2 yum 删除法
( ?9 Z) P+ f: X! [5 A
yum remove kernel-(要删除的版本)
& Z: }2 I8 A& ~" l8 R
8 p8 l8 a: i2 s/ J9 C- A
3.3 手动删除
( q5 A( q- n7 E2 A5 R* C; z" E
删除/lib/modules/目录下不需要的内核库文件
- M) B2 k+ c1 g: ]( k9 o
删除/usr/src/kernel/目录下不需要的内核源码
: Z( ]% `& R5 S9 D _9 q
删除/boot目录下启动的核心档案禾内核映像
3 b! k5 V) D- w7 j1 L( n; S" {
更改grub的配置,删除不需要的内核启动列表
@2 M. Z/ t/ L/ ]
, @1 R* X( }) m9 y) y& X
; S u/ ]% k; I3 W9 ?
9 m, Z5 U# A8 K
4. 内核开发的特点
) o, }9 r; P0 P1 @! Q! d$ ?' F- M
4.1 无标准C库
2 P! H; |- b8 i) n
为了保证内核的小和高效,内核开发中不能使用C标准库,所以连最常用的printf函数也没有,但是还好有个printk函数来代替。
( y9 p/ x2 w& Q* ]1 u
6 j9 K* s* A. a6 z( U
4.2 使用GNU C,推荐用gcc 4.4或以后的版本来编译内核
7 L) y- G. q- z6 C \: z1 J* p
因为使用GNU C,所有内核中常使用GNU C中的一些扩展:
1 Q' y, @! B2 F* C( c7 D
4 A5 Y O+ w7 k7 Y2 C, M2 D* x
4.2.1 内联函数
1 J8 z2 u" w( x6 a! ]) L B6 O7 P
内联函数在编译时会在它被调用的地方展开,减少了函数调用的开销,性能较好。但是,频繁的使用内联函数也会使代码变长,从而在运行时占用更多的内存。
4 W; A, |4 P; w2 z+ `
$ V4 n5 `6 z# X$ {, B4 a
所以内联函数使用时最好要满足以下几点:函数较小,会被反复调用,对程序的时间要求比较严格。
% o6 W+ j. U" h- m' v
% s* H. a5 p. v# j. a, Z) n
内联函数示例:static inline void sample();
4 k# \5 p/ }/ ^7 S
3 N' w& ^/ s7 z7 y4 H* \
4.2.2 内联汇编
0 s8 g4 ^ @5 h2 w' b! o% a
内联汇编用于偏近底层或对执行时间严格要求的地方。示例如下:
( n3 P+ \1 L! o/ Y/ m" `
2 o' n, Y5 S# L) h
unsigned int low, high;
4 `8 p- h- T \5 W& |8 j" y3 i
asm volatile("rdtsc" : "=a" (low), "=d" (high));
3 \- ?2 S6 w9 ^
/* low 和 high 分别包含64位时间戳的低32位和高32位 */
/ E) ]- S( u! J) o( r5 Y9 d% ~
4.2.3 分支声明
. I3 u W& A! f t1 R, Z' `
如果能事先判断一个if语句时经常为真还是经常为假,那么可以用unlikely和likely来优化这段判断的代码。
' D5 V% k# Q- C+ P! R
: \; }, M, D, [' T
复制代码
4 V a0 S* d! M3 ]0 ?
/* 如果error在绝大多数情况下为0(假) */
# S% C, ~, B# C' f% R$ ^
if (unlikely(error)) {
7 k2 r0 j N; H. K
/* ... */
3 V: D9 y! l, U) L; ^
}
. z1 @& ], s( O. X# \
; R' a3 j3 r2 a0 I7 a' l3 G- h
/* 如果success在绝大多数情况下不为0(真) */
8 _) W1 g1 z, u" H# W
if (likely(success)) {
5 a' R! y: h" R" j7 ~8 Q
/* ... */
; X( B8 `0 H6 z9 K1 C/ n7 S
}
4 J' f9 Q$ C, C
复制代码
/ E3 V% q8 C; i2 e r. H
4.3 没有内存保护
- V2 `3 t3 ~, m3 y& m( S
因为内核是最低层的程序,所以如果内核访问的非法内存,那么整个系统都会挂掉!!所以内核开发的风险比用户程序开发的风险要大。
8 D* c$ R* u9 @1 M* x! H, O8 N
; X2 d% w& l/ x; Z% K- C s! ^7 C
而且,内核中的内存是不分页的,每用一个字节的内存,物理内存就少一个字节。所以内核中使用内存一定要谨慎。
1 M0 ~# O; J0 I* K
/ L4 G5 S3 c& @( f' Q& c
4.4 不使用浮点数
. |3 c/ A) l' w" V V$ o
内核不能完美的支持浮点操作,使用浮点数时,需要人工保存和恢复浮点寄存器及其他一些繁琐的操作。
* y5 H8 o. T5 S$ s5 S! k) v5 H* E
* p7 @ R! ^$ ^ U5 {( o2 u
4.5 内核栈容积小且固定
# {# Y1 ], X7 f$ H5 i. g
内核栈的大小有编译内核时决定的,对于不用的体系结构,内核栈的大小虽然不一样,但都是固定的。
/ ^8 J% \4 h" n" c4 i m
7 c9 G6 B- S6 E
查看内核栈大小的方法:
. N' \ A& ~, o: \
% t$ {% ]9 c- r: E, m7 n$ ^: ?
ulimit -a | grep "stack size"
) O" x/ Y' u4 \# _& j8 C
4.6 同步和并发
/ {/ g, Z" m6 t6 Q0 \" k
Linux是多用户的操作系统,所以必须处理好同步和并发操作,防止因竞争而出现死锁。
4 w/ c Q! s0 ~7 F8 r$ p
. v' }2 ~4 c+ P; v( q& l
4.7 可移植性
8 u! @3 ~ ]9 `
Linux内核可用于不用的体现结构,支持多种硬件。所以开发时要时刻注意可移植性,尽量使用体系结构无关的代码。
作者:
xiaogegepcb
时间:
2020-9-24 16:05
Linux内核设计与实现之内核开发的准备
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2