软件开发与易经描述的卦象,有异曲同工之处,现今种类繁多的编程语言、开发框架,好比六十四卦,追根溯源,终究会回归到最初的太极图;软件开发而言,这些开发语言、框架,也就最终都会回归到操作系统。所以有了操作系统连载篇章,记录自己学习操作系统的历程。
首先来了解什么是操作系统:"操作系统就是一个运行于硬件上的特殊软件!"
PC计算机系统
上图为现代计算机系统架构,可以看到,操作系统位于硬件层、BIOS之上,简而言之,也就是一个软件,这个软件管理着硬件资源、软件资源。用户软件经过编译软件编译后,运行于操作系统上,操作系统对其进行管理、调度等统筹工作。
-- BIOS是啥玩意?
在上图中,操作系统与硬件层之间,有一个BIOS的东西,那么BIOS是啥?我们知道,操作系统是软件,软件是不能直接单刀直入的运行于硬件之上,而需要借助其他力量,而BIOS(输入输出系统)扮演的就是这个角色,在我们开机时出现的蓝色操作界面,就是BIOS运行的效果,如下:
BIOS操作界面供我们选择从哪里启动操作系统,如果重装操作系统或者装了双系统的朋友,就是会看到会让选择从哪里启动操作系统(硬盘、USB等),BIOS是直接固化在硬件中的固件,出厂时已经烧写完成,不可更改,如果一台电脑的BIOS坏了,那么这台电脑也就寿终正寝了。BIOS作用是操作系统与硬件层的桥梁,开机时拉起操作系统。
-- 操作系统启动流程
以上了解了BIOS,现在来了解电脑如何从开机一步步进入到漂亮的操作系统界面的。
在上图中,可以看到现代操作系统的启动流程,BIOS的工作使命就是硬件初始化、建立中断向量表,然后加载主引导程序,主引导程序一旦开始执行,BIOS的任务可以说结束了,主引导程序同样会进行一系列的初始化工作,最终加载运行操作系统内核,之后便是操作系统初始化,然后就进入操作系统了。这里我把流程分为三大块:
开机自动执行BIOS --> 拉起主引导程序 --> 拉起操作系统内核 --> 操作系统从此可以自嗨
疑问一、如何开机自动执行BIOS?
BIOS既然是固件,那么就肯定存在硬件某个地址处,这个地址就是0XFFFF0,也就是执行BIOS的入口地址,硬件的特殊设计,使得CPU在开机时自动从0XFFFF0地址开始执行,也就解答了为啥开机就自动执行BIOS。
疑问二、BIOS如何拉起主引导程序执行?
上边说了,BIOS操作界面会选择什么介质启动操作系统,在选择具体的启动介质后,将启动介质中主引导区的主引导程序加载到内存,主引导程序一般位于主引导区的前512字节,并且主引导程序入口地址固定为0X7C00,拉起主引导程序,也就是跳转到0X7C00地址处执行而已, 汇编语言中就是一个jmp指令,继而将控制权交给主引导程序。
疑问二、如何寻找主引导区?如何获取主引导程序?
主引导区固定位于启动介质的开始地址处,大小为512字节,这512字节的内容,就是主引导程序,需要注意的一点是,512字节最后两字节固定为0X55AA
以上说明了系统的启动流程,下边用一张详细的图来总结:
总结:
1、BIOS是计算机上电后第一个运行的程序
2、BIOS对硬件等进行必要的初始化,并加载运行主引导程序
3、主引导程序位于启动介质的最开始512字节处,该512字节以0X55AA结束
4、主引导程序继续完善初始化工作,并加载运行操作系统内核
嵌入式系统
嵌入式系统与传统的PC一样,也是一种计算机系统,是由硬件和软件组成的。一般而言,典型的嵌入式系统的又可以进一步分成四个部分:嵌入式处理器、嵌入式外围设备、嵌入式操作系统和嵌入式应用软件,如下图所示:
嵌入式处理器
嵌入式处理器是嵌入式系统硬件平台的核心。嵌入式处理器与通用处理器最大的不同点在于,嵌入式CPU大多工作在为特定用户群所专门设计的系统中,它将通用CPU中许多由板卡完成的任务集成到芯片内部,从而有利于嵌入式系统在设计时趋于小型化,同时还具有很高的效率和可靠性。 嵌入式处理器的体系结构经历了从CISC(复杂指令集)至RISC(精简指令集)和Compact RISC的转变,位数则由4位、8位、16位、32位逐步发展到64位。目前常用的嵌入式处理器可分为低端的嵌入式微控制器(Micro Controller Unit,MCU)、中高端的嵌入式微处理器(Embedded Micro Processor Unit,EMPU)、用于计算机通信领域的嵌入式DSP处理器(Embedded Digital Signal Processor,EDSP)和高度集成的嵌入式片上系统(System On Chip,SOC)。
目前几乎每个半导体制造商都生产嵌入式处理器,并且越来越多的公司开始拥有自主的处理器设计部门,据不完全统计,全世界嵌入式处理器已经超过1000多种,流行的体系结构有30多个系列,其中以ARM、PowerPC、MC 68000、MIPS等使用得最为广泛。
嵌入式外围设备
在嵌入系统硬件系统中,除了中心控制部件(MCU、DSP、EMPU、SOC)以外,用于完成存储、通信、调试、显示等辅助功能的其他部件,事实上都可以算作嵌入式外围设备。外部设备在不同的系统中有不同的选择。例如,在汽车上,外部设备主要是传感器;而在一般手机上,外部设备可以是键盘、液晶屏幕等。
嵌入式操作系统
嵌入式操作系统是用来支持嵌入式应用的系统软件,是嵌入式系统极为重要的组成部分,通常包括与硬件相关的底层驱动程序、系统内核、设备驱动接口、通信协议、图形用户界面(GUI)等。嵌入式操作系统具有通用操作系统的基本特点,如能够有效管理复杂的系统资源,能够对硬件进行抽象,能够提供库函数、驱动程序、开发工具集等。但与通用操作系统相比较,嵌入式操作系统在系统实时性、硬件依赖性、软件固化性以及应用专用性等方面,具有更加鲜明的特点。
嵌入式应用软件
嵌入式应用软件是针对特定应用领域,基于某一固定的硬件平台,用来达到用户预期目标的计算机软件,由于用户任务可能有时间和精度上的要求,因此有些嵌入式应用软件需要特定嵌入式操作系统的支持。嵌入式应用软件和普通应用软件有一定的区别,它不仅要求其准确性、安全性和稳定性等方面能够满足实际应用的需要,而且还要尽可能地进行优化,以减少对系统资源的消耗,降低硬件成本。
ARM处理器
确切地说ARM处理器不是指某种处理器,而是采用ARM体系结构开发的处理器。可以说说ARM处理器是目前在嵌入式领域最重要的处理器。目前有数十家公司使用ARM体系结构开发自己的芯片,支持的外部设备和功能丰富多样。
1.3.1ARM处理器介绍
通常人们认为ARM(Advanced RISC Machine)是一家公司的名字,也可以认为是一类处理器的统称,还可以认为是一种技术的名字。
ARM公司于1991年成立于英国剑桥,是微处理器行业的一家知名企业,自己本身并不生产芯片,而是主要通过出售芯片设计技术的授权获取利润。该企业设计了大量低成本、高性能、低功耗的RISC处理器、 相关技术及软件。
目前,采用ARM技术知识产权(IP核)的微处理器,即通常所说的 ARM微处理器,已遍及工业控制、消费类电子产品、通信系统、网络系统、无线系统 等各类产品市场。基于ARM技术的微处理器应用约占据了32位RISC微处理器80%以 上的市场份额,其中在手机市场,ARM占有绝对的垄断地位。
1.3.2ARM体系结构的发展
体系结构,定义了指令集(ISA)和基于这一体系结构下处理器的编程模型。 基于同种体系结构可以有多种处理器,每个处理器性能不同,所面向的应用也就不 同,但每个处理器的实现都要遵循同一体系结构。
1983年ARM公司开始ARM的设计,早期的V1结构、V2结构有26位的寻址空间,现已废弃不用。在1980年代晚期的V3结构将寻址范围扩展到32位,是ARM质一般的飞跃。后来V4结构不再强制要求与以前的26位体系结构版本兼容,它清楚地指明了哪个指令会引起未定义指令异常发生,V4结构可谓是真正地得到了推广,值得一提的是16位指令集Thumb指令集就是在这个版本上成立的。
V5结构在版本4的基础上,对现在指令的定义进行了必要的修正,对版本4体系结构进行了扩展,并增加了指令。V5结构的ARM处理器提升了ARM和Thumb两种指令的交互工作能力,同时 有了DSP指令—V5E结构、Java指令—V5J结构的支持。
ARM体系结构版本6是2001年发布的,该版本增加了媒体指令。属于V6体系结构的处理器核有ARM11(2002年发布)。V6体系结构包含ARM体系结构中所有的4种特殊指令集:Thumb指令(T)、DSP指令(E)、Java指令(J)和Media指令。
ARM体系结构版本V7是在版本V6基础上诞生的。V7结构采用了Thumb-2技术,它是在ARM的Thumb代码压缩技术的基础上发展起来的,并且保持了对现存ARM解决方案的完整的代码兼容性。V7结构还采用了NEON技术,将DSP和媒体处理能力提高了近4倍。并支持改良的浮点运算,满足下一代3D图形、游戏以及传统嵌入式控制应用的需求。从此版本开始,ARM公司正式将以前的版本ARM处理器称为经典系列,V7结构及以后处理器称为Cortex系列,并且将 Cortex系列产品分为A(应用处理)、R(实时控制)、M(微控制)三个子系列。
ARM在2012年下半年首次发布采用64位V8架构产品。V8是ARM公司的第一款64位处理器架构,包括AArch64和AArch32二种主要执行状态。其中前者引入了一套新的指令集“A64”专门用于64位处理器,后者后者用来兼容现有的32位ARM指令集。目前我们看到的Cortex-A53, Cortex-A57(现在被A72替代了)二款处理器便属于Cortex-A50系列。
1.3.3ARM处理器
芯片厂家获得ARM公司的授权以后生成出来不同的处理器,ARM处理器的支持(如指令语义)的实现细节可能会有所不同。根据结构体系及内核的差异,目前ARM处理器又分为不同的系列,如下表所示:
表1ARM处理器内核列表
架构 处理器家族
ARMv1 ARM1
ARMv2 ARM2、ARM3
ARMv3 ARM6、ARM7
ARMv4 StrongARM、ARM7TDMI、ARM9TDMI
ARMv5 ARM7EJ、ARM9E、ARM10E、XScale
ARMv6 ARM11、ARM Cortex-M
ARMv7 ARM Cortex-A、ARM Cortex-M、ARM Cortex-R
ARMv8 Cortex-A35、Cortex-A50系列、Cortex-A72、Cortex-A73
世界各大半导体生产商从ARM公司购买其设计 的 ARM 微处理器核,根据各自不同的应用领域,加入适当的外围电路,从而形成自 己的 ARM 微处理器芯片进入市场,又形成了各自的ARM系列芯片。典型的如基于Cortex-M3内核的意法半导体STM32 系列芯片,基于ARM920T内核的Samsung S3C2442和 S3C2410芯片 ,基于ARM7TDMI(-S)内核的恩智浦半导体LPC2000及LH754xx系列芯片等。
1.4Linux操作系统
应用于嵌入式系统的的嵌入式操作系统很多,如Linux、uCOS-II、WinCE等,其中Linux系统是应用最为广泛的。 Linux系统是一个免费使用的类似Unix的操作系统,最初运行在X86体系结构,目前已被移植到数十种处理器上,如ARM、LoongSon等。Linux最初是由芬兰的Linux Torvalds设计开发,经过多年的发展,已经形成一个非常庞大、功能完善的操作系统。
嵌入式Linux是以Linux为基础的嵌入式操作系统,它被广泛应用在移动电话、媒体播放器、消费性电子产品以及航空航天等领域。嵌入式Linux是将Linux操作系统进行裁剪修改,使之能在嵌入式计算机系统上运行的一种操作系统。嵌入式Linux既继承了Internet上无限的开放源代码资源,又具有嵌入式操作系统的特性。嵌入式Linux的特点是版本免费,而且性能优异,软件移植容易,代码开放,有许多应用软件支持,应用产品开发周期短,新产品上市迅速,稳定性好、安全性好。
1.4.1Linux内核版本
严格来讲,Linux这个词本身只表示Linux内核,任何使用Linux内核的操作系统都可以称为Linux操作系统。 内核,是一个操作系统的核心。是基于硬件的第一层软件扩充,提供操作系统的最基本的功能,是操作系统工作的基础,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。Linux内核的主要模块(或组件)分以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信,以及系统的初始化(引导)、系统调用等。
Linux内核是源码开源的,源代码可至https://www.kernel.org下载。另外网站https://elixir.bootlin.com/linux/latest/source,提供了在线工具帮助我们阅读有关代码。
Linux内核版本号一般由3组数字组成:X.Y.Z。X表示主版本号,Y表示次版本号,Z表示修订版本号。早期次版本号为奇数时代表的是不稳定版本,偶数时代表稳定版本。目前Linux内核的最新的稳定版本为5.1.10版。
小技巧:如何查看Linux内核版本号?
在Linux终端中输入 uname -a
1.4.2Linux发行版本
Linux系统是开放的,任何人都可以制作自己的系统。Linux 主要作为Linux发行版(通常被称为"distro")的一部分而使用。这些发行版由个人,松散组织的团队,以及商业机构和志愿者组织编写。它们通常包括了其他的系统软件和应用软件,以及一个用来简化系统初始安装的安装工具,和让软件安装升级的集成管理器。大多数系统还包括了像提供GUI界面的XFree86之类的曾经运行于BSD的程序。 一个典型的Linux发行版包括:Linux内核,一些GNU程序库和工具,命令行shell,图形界面的X Window系统和相应的桌面环境,如KDE或GNOME,并包含数千种从办公套件,编译器,文本编辑器到科学工具的应用软件。
发行版为许多不同的目的而制作, 包括对不同计算机结构的支持, 对一个具体区域或语言的本地化,实时应用,和嵌入式系统,甚至许多版本故意地只加入免费软件。已经有超过三百个发行版被积极的开发,最普遍被使用的发行版有大约十二个。在如下https://www.linux.org/pages/download可以找到当前较为流行的Linux发行版本的下载。
小技巧:如何查看Linu发行版本号?
在Linux终端中输入 lsb_release -a
嵌入式linux启动流程
1、嵌入式linux启动第一步----Boot Loader
Boot Loader在这里我就不细说了,详细分析起来的话有很多内容,网上也有很多讲解很详细的文章。这段小程序中我们可以初始化硬件设备、建立内存空间的映射图,将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核做好一切准备。
2、嵌入式linux启动第二步----加载内核
假如你是从u-boot启动的话,可能会有很多方式来实现内核的加载。系统读取内存映像,并进行解压缩操作,此时屏幕一般会有一些供调试用的打印信息。内核解压好之后,系统将解压后的内核放在内存之中,并调用start_kernel()函数来启动一系列的初始化函数并初始化各种设备,完成Linux核心环境的建立。至此Linux内核已经建立起来了,也就是说核心的任务调度、多用户什么的功能都齐全了。可能有人会问我们在Boot Loader里面不是已经初始化了硬件了么?怎么还要初始化设备。这里原因说不好,Boot Loader里面确实是初始化了一些硬件设备,但是那些初始化只是临时的,系统起来之后的初始化会覆盖掉。你可以理解为Boot Loader里面初始化算是游击、土八路,真正系统起来才是正规军。
3、嵌入式linux启动第三步----用户层init依据inittab文件来设定运行等级
内核加载后,第一个运行的程序便是/sbin/init,该文件会读取/etc/inittab文件,并依据此文件来进行初始化工作。其实/etc/inittab文件最主要的作用就是设定Linux的运行等级,其设定形式是“xxx1:xxx2:xxx3:xxx4”其中xxx1是指入口标识符,xxx2是指init所处的运行等级,xxx3是指action,描述process的运行方式,xxx4是指process。
运行等级设定如下:
0:关机
1:单用户模式
2:无网络支持的多用户模式
3:有网络支持的多用户模式
4:保留,未使用
5:有网络支持有X-Window支持的多用户模式
6:重新引导系统,即重启
4、嵌入式linux启动第四步----init进程执行rc.sysinit
在设定了运行等级之后,Linux系统执行的第一个用户文件就是/etc/rc.d/rc.sysinit脚本程序,它做的工作非常多,包括设定PATH、设定网络配置(/etc/sysconfig/network)、启动swap分区、设定/proc等等。
5、嵌入式linux启动第五步----启动内核模块
依据/etc/modules.conf文件或/etc/modules.d目录下的文件来装载内核模块。
6、嵌入式linux启动第六步----执行不同运行级别的脚本程序
根据不同的级别设置,运行rc0.d到rc6.d中的相应的脚本程序,来完成相应的初始化工作和启动相应的服务。
7、嵌入式linux启动第七步----执行/etc/rc.d/rc.local
这是linux留给用户进行个性化的地方。可以把想设置和启动的东西放到这里。
8、嵌入式linux启动第八步----执行/bin/login程序,进入登陆状态