目录
一、前言
之前的嵌入式系统及应用是比较通用的知识点,操作系统可以解决并发、性能分析和冲突解决、资源管理、隐藏复杂性的接口(复杂留给自己,简单留给用户)。主流的操作系统包括Unix(IOS,HP),Linux(ubuntu,debian,开源),Windows(微软)。
二、基本知识
操作系统OS是一个系统软件,管理计算机的软硬件资源HAL,并为计算机程序APP提供服务。OS 管理 硬盘,CPU,键盘,文件,内存。
操作系统的五大功能包括文件管理、进程管理(CPU)、操作系统接口(应用程序调用系统接口->OS响应系统接口执行硬件底层)、内存管理、外设管理(打印机键盘)。
进程的管理包括进程控制(创建、终止)、进程调度(OS调度)、进程通信、进程同步(外设资源竞争)。
内存管理包括内存分配、内存保护、地址映射、内存扩充。
设备管理包括设备分配(IO请求)、设备处理(读取)、缓冲处理(数据缓冲)。
文件管理主要管理外存上的文件、包括存储空间管理、目录管理、读写管理、权限管理,把文件的存取共享和保护手段提供给用户。
操作系统(OS)特征包括并发性、共享性、虚拟性、异步性
现代操作系统的组成:
操作系统发展:手工阶段(电子管时代),单道批处理系统(作业),多道批处理系统(多CPU),分时操作系统(解决无法用户交互问题,unix,linux,主要是交互性),实时操作系统(及时性、可靠性)、嵌入式操作系统(全部软硬件资源分配,任务调度,Android,vxWork,RTLinux等)、个人计算机操作系统(MS-DOS,Windows,Linux,MacOS)、网络操作系统(提供网络通信和网络服务功能的OS,NOS)、分布式操作系统(多台计算机可以通讯,共享CPU内存等更多资源,看起来是一个操作系统DOS)
分布式操作系统:
分布式操作系统(右)和网络操作系统(左)区别:
三、操作系统结构
OS设计原则可靠性、可移植性、可维护性、有效性、功能性;结构包括模块化结构OS,分层式结构OS、微内核结构OS。
模块化结构OS(Linux)按照模块进行划分,优点是模块之间可以直接调用函数,没有额外开销,性能比较高;缺点是模块间的依赖关系复杂,函数调用的深度比较深。
分层结构OS从资源管理的观点出发,采样自顶向下的设计原则,每一层都是建立在可靠基础上,规定每一层只能调用下一层;优点调式容易,子模块调用有序;缺点性能低;
微内核结构操作系统将操作系统划分为两大部分微内核(客户)和多个服务器;采用机制和策略分离的设计原则,将机制部分和硬件紧密相关的部分放入微内核,包括进程管理、低级内存管理、中断及陷入处理等,另外的绝大部分放在服务器实现。
优点是可扩展性、可移植性、可靠性都比较好。
客户和服务器、服务器之间采用消息通讯机制进行的,该结构可以很好的支持分布式和网络系统
相比于模块结构,微内核OS性能有所下降,在于客户和服务器之间的通信代价。用户请求OS服务是宏内核需要两次上下文切换(a所示),但微内核需要四次上下文切换
微内核OS包括QNX(黑莓),HarmonyOS(华为鸿蒙);宏内核OS包括Linux,ORACLE,FreeBSD,MSDOS。
区别:
微内核提升进程间通信效率提高性能;宏内核的可维护性差可以通过可加载的Linux内核模块实现、eBPF机制。
CPU状态包括内核态和用户态:
CPU运行现场:
Linux内核模块与C应用的对比:
四、Linux内核及可加载内核模块
Linux系统整体结构,分为两部分应用软件和操作系统内核,接口是系统调用。
上图最左侧“模块”不需要直接操作内核(不和内核紧耦合),就可以集成开发者模块,这种机制叫做可加载的Linux内核模块,即在Linux内核运行的过程中,可以把一个模块加载到Linux内核中。当不需要该模块时可以从内核中卸载。
Linux的内核编程不再使用如printf这样的库函数,而是Linux内核的源码,如printk(kernal.h),lkp_init函数模块的初始化函数,它是加载模块的入口函数,lkp_exit()是出口函数,也是卸载模块函数。
如何编译内核模块?必须去写Makefile文件,定义三个变量,当前路径变量、存放内核版本号、存放内核源码所在路径
如何进行插入操作?使用超级用户权限插入。
模块插入命令:insmod module_example.ko模块ko文件,模块删除命令:rmmod,查看模块信息命令:dmesg
五、内核模块的插入和删除
流程: 编写模块helloworld.c,编写Makefile文件,编译生成ko文件,插入模块
//支持init exit宏
#include <linux/init.h>
#include <linux/kernel.h>
//支持linux模块机制
#include <linux/module.h>
//入口函数
static int __init lkm_init(void)
{
//可以指定消息的打印级别
printk("Hello world\n");
return 0;
}
//出口函数
static void __exit lkm_exit(void)
{
printk("Goodbye world\n");
}
//指定入口点,引导内核
module_init(lkm_init);
module_exit(lkm_exit)
//声明许可证
MODULE_LICENSE("GPL");
Makefile文件
使用目标文件helloworld.o建立一个模块,生成模块的名字是helloworld.ko
obj-m:=helloworld.o
当前路径
CURRENT_PATH := $(shell pwd)
内核版本
LINUX_KERNEL := $(shell uname -r)
内核路径
LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL)
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH)编译放在哪个目录 modules 表明是内核模块
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
编译:直接make,生成.ko文件
内核的加载调用不再使用终端,在proc下(虚拟文件系统),可以访问有关内核的状态,进程的信息。在meminfo中保存了物理内存和交换空间的信息。Kmsg包含了所有的日志信息,查看日志使用dmesg命令。
插入模块:
sudo insmod helloworld.ko
使用lsmod查看当前系统的模块
使用dmesg命令打印系统日志信息
卸载模块:
sudo rmmod helloworld