Linux 内核开发——内核简介

内核简介

Linux 构成


Linux 为什么被划分为系统空间和内核控件

隔离核心程序和应用程序,实现对核心程序的保护,如保护操作系统本身的保护。


什么内核空间,用户空间

内核空间和用户空间是程序运行的两种不同的状态,Linux对自身软件系统进行了划分,一部分核心的软件独立于普通的软件,拥有特权级别,能够访问平台的所有硬件和资源,称为“内核空间”。而普通的软件运行在“用户空间”,它只拥有有限的系统资源,不能直接访问内核空间和硬件资源。

将系统分为“内核空间”和“系统空间”能提高系统的安全性,能够避免一些恶意程序的窥探,也能避免一些低劣的普通程序影响核心系统的运行,能够有效的保证系统的稳定性。


内核构成

SCI

为用户空间提供了一套统一的系统调用函数来访问Linux内核,是用户空间到内核空间的桥梁。

Glibc

GNU发布的libc库,也是C运行库,是Linux中最底层的API,几乎所有的app都依赖于Glibc,它除了封装Linux系统提供的系统函数以外,其自身也提供了很多其他的功能的函数库,主要的库函数如下:

(1)string库,字符串处理库函数

(2)signal库,提供信号处理库函数

(3)dlfcn库,管理共享库的动态加载函数库

(4)directory库,文件目录操作函数

(5)elf库,共享库的动态加载器,也即interpreter

(6)iconv,不同字符集的编码转换

(7)sockets,socket接口库

(8)Date and Time,日期和时间

(9)input/output,输入输出流

(10)linux threads库,LINUX线程库函数

11)locale库,本地化和国际化的接口库

(12)Character库,字符处理

13)Memory库,动态内存的分配与管理

(14)Processes and job control库,进程和进程控制库

15)stdlib库,其它基本功能 

内存管理:

控制多个进程安全的共享有限的内存区域。

进程管理:

进程管理的主要任务包括进程的创建、停止、进程间通信,还包括不同的进程共享CPU

VFS

虚拟文件系统隐藏了不同文件系统的细节,为文件操作提供了统一的接口。

网络协议栈:

提供丰富的网络协议实现。

设备驱动:

内核中大量的源码都是在驱动中实现的,它们控制着特定的硬件设备。

 

ARM 有哪些工作模式

用户模式(user)

快速中断模式(frq)

外部中断模式(irq)

管理模式(svc)

数据访问终止(abt)

系统模式(sys)

为定义指令异常(und)

不同模式下有不同权限,如寄存器权限

内核空间和用户空间如何转换

硬件中断和系统调用可以实现用户空间跳转到内核空间运行

 

Linux内核源代码

内核源代码下载地址:www.kernel.org

 

内核目录结构

Arch(Architecture):内核支持的每一种CPU体系,在该目录下都有一个子目录,每个不同的CPU子目录又都分为boot(系统引导)mm(内存管理)kernel(内核特性相关实现)等子目录。

|--x86 /*英特尔CPU及与其体系结构兼容的子目录*/

||--boot /*引导程序*/

|||--compressed /*内核解压缩*/

||--tools /*生成压缩内核印象的程序*/

||--kernel /*内核特性相关的实现,如信号处理、时钟处理*/

||--lib /*硬件相关工具函数*/

 

目录结构

Linux source code

├─ boot 系统引导汇编程序

├─ fs 文件系统

│ ├─ devpts /*/dev/pts虚拟文件系统*/

│ ├─ ext2 第二扩展文件系统

│ ├─ fat MS fat32文件系统

├─ block 部分块设备驱动程序

├─ crypto 加密、压缩、CRC校验算法

├─ 内核的文档

├─ drivers 设备驱动程序 

├─ include 头文件(*.h) 内核所需的头文件,与平台相关的头文件放在相应的字目录下

│ ├─ asm CPU 体系结构相关的部分

│ ├─ linux  Linux 内核专用部分,与平台无关的头文件

│ └─ sys 系统数据结构部分

├─ init 内核初始化程序

├─ IPC 进程间通信的实现代码

├─ samples 一些内核编程的范例

├─ scripts 配置内核的脚本

├─ sound 音频设备的驱动程序

├─ usr cpio 命令实现

├─ virt 内核虚拟机

├─ kernel 内核进程调度、信号处理、系统调用等程序

│ ├─ blk_drv 块设备驱动程序

│ ├─ chr_drv 字符设备驱动程序

│ └─ math 数学协处理器仿真处理程序

├─ lib 内核库函数

├─ mm 内存管理程序

└─ tools 生成内核Image 文件的工具程序

 

Linux内核配置与编译



内核模块

什么是内核模块

内核模块就是为内核或者其他内核模块提供功能的代码块,内核模块具有举例的功能,能独立的编译,但是需要在内核环境下才能运行。它在运行时被链接进内核作为内核的一部分在内核空间运行。内核模块的存在提高了单内核可可扩展性差、可维护性差的缺陷。

 

如何使用内核模块

方法一:

将所有的内核组件都编译进内核,生成zImage或者bzImage文件。

缺陷:内核文件过大、新增/删除内核组件的时候需要重新编译源码

方法二:

zImage或者bzImage文件并不包含任何组件,只是在需要用到某个组件的时候,动态的将内核组件添加到内核中去。

 

内核模块的特点

1)模块本身并不被编译进内核文件

2)可根据需求,在内核运行期间,动态的添加或者卸载

 

内核模块缺陷

增加了管理内核模块的开销

内核版本与模块版本不兼容,会导致系统崩溃

增加内存、中断、符号表等资源消耗

 

内核模块的编译

Makefile

 
ifneq ($(KERNELRELEASE),)
#“hello”是模块的名称,只有“hello”可变。
obj-m := hello.o
hello-objs := file1.o file2.o
 
else
 
#内核源代码的位置
KDIR := ~/kernel/
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.c *.mod.o *.symvers
endif

 

内核模块的安装与卸载

命令:

1) insmod 加载内核模块

2) rmmod 卸载内核模块

3)lsmod 查看已经存在的内核模块

4)modprobe 加载内核模块

modprobe 与 insmod的区别在于,modprobe能处理内核模块之间的依赖关系,它能够根据/lib/modules/version/modules.dep 文件所描述的依赖关系来加载此模块所需的其他内核模块。

 

内核模块与应用程序的差别

1) 应用程序在执行完成后会从内存中消失

2) 内核模块会在执行该模块前将其注册到内核中去,当完成初始化函数后仍然处于内核中,直到被卸载

 

内核模块相关宏

1) MODULE_LICENSE("GPL");

2) MODULE_AUTHOR("Jack Chen");

3) MODULE_DESCRIPTION("Hello World");

4) MODULE_ALIAS("A simple module");

5) MODULE_VERSION("V1.0");

 

带参数的内核模块

可以使用宏module_param(name,type,perm)声明输入参数,其中:

1) name 表示参数的名称

2) type 表示参数的类型,常见的类型有int(整形)charp(字符串类型)

3) perm 访问权限

a) S_IRUGO 任何用户都对/sys/module中出现的该参数具有读权限

b) S_IWUSR 允许root用户修改/sys/module 中出现的该参数

 

#include<linux/init.h>
#include<linux/module.h>
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jack Chen");
MODULE_DESCRIPTION("Hello World");
MODULE_ALIAS("A simple module");
MODULE_VERSION("V1.0");
 
static int age = 10;
static char* name = "Jack chen";
 
module_param(age,int,S_IRUGO);
module_param(name,charp,S_IRUGO);
 
static int hello_init(void)
{
printk(KERN_EMERG" age:%d\n",age);
printk(KERN_EMERG" name:%s\n",name);
return 0;
}
 
static void hello_exit(void) 
{
printk("<3>Goodbye,world !\n");
}
 
module_init(hello_init);
module_exit(hello_exit);

 

PS:使用insmod命令时的语法为 insmod hello.ko age=27 name=David

 

内核模块的导出

用于向其他内核模块提供功能函数,否则其他内核模块无法使用模块内的功能函数,其中/proc/kallsyms记录了内核中所有导出符号的名字和地址。

1) EXPORT_SYMBOL(符号名)

2) EXPORT_SYMBOL_GPL(符号名适用于包含了GPL许可证的的内核模块

使用EXPORT_SYMBOL声明后的符号将添加在/proc/kallsyms 文件中,可以使用cat/proc/kallsyms | grep 符号名 查询

 

[calculate.c]

#include <linux/init.h>                                
#include <linux/module.h> 
                               
MODULE_LICENSE("GPL");                                
                                
int add_integar(int a,int b)                                
{                                
return a+b;                             
} 
                               
int sub_integar(int a,int b)                                
{                                
return a-b;                             
}                            
 
static int __init sym_init()
{
    return 0;
}
 
static void __exit sym_exit()
{
 
}
 
module_init(sym_init);
module_exit(sym_exit);
 
EXPORT_SYMBOL(add_integar); 
EXPORT_SYMBOL(sub_integar);
 

[hello.c]

#include <linux/module.h>
#include <linux/init.h>
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jack Chen");
MODULE_DESCRIPTION("Hello World");
MODULE_ALIAS("A simple module");
MODULE_VERSION("V1.0");
 
extern int add_integar(int a,int b); 
extern int sub_integar(int a,int b);
 
static int hello_init()
{
    int res = add_integar(1,2);
    printk("<3> res:%d\n",res);
    return 0;
}
 
static void hello_exit()
{
    int res = sub_integar(2,1);
    
    printk("<3> res:%d\n",res);
}
 
module_init(hello_init);
module_exit(hello_exit);

printk 的优先级

1) printk的日志级别定义如下(在linux26/includelinux/kernel.h中): 

2) #defineKERN_EMERG"<0>"/*紧急事件消息,系统崩溃之前提示,表示系统不可用*/

3) #defineKERN_ALERT"<1>"/*报告消息,表示必须立即采取措施*/

4) #defineKERN_CRIT"<2>"/*临界条件,通常涉及严重的硬件或软件操作失败*/

5) #defineKERN_ERR"<3>"/*错误条件,驱动程序常用KERN_ERR来报告硬件的错误*/

6) #defineKERN_WARNING"<4>"/*警告条件,对可能出现问题的情况进行警告*/

7) #defineKERN_NOTICE"<5>"/*正常但又重要的条件,用于提醒。常用于与安全相关的消息*/

8) #defineKERN_INFO"<6>"/*提示信息,如驱动程序启动时,打印硬件信息*/

9) #defineKERN_DEBUG"<7>"/*调试级别的消息*/


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。