嵌入式软件的体系结构:
1:无操作系统的嵌入式软件:
早期在嵌入式的应用范围主要集中在控制领域,硬件的配置比较低,嵌入式软件的设计主要以应用为核心,
应用软件直接建立在硬件,没有专门的操作系统,软件规模也很小。
无操作系统的嵌入式软件主要采用循环轮转和中断两种实现方式。
循环轮转方式:
循环轮转方式的基本设计思想是:把系统的功能分解为若干个不同的任务,放置在一个永不结束的循环语句中,
按照时间顺序逐一执行。当程序执行完一轮后,又回到程序的开头重新执行,循环不断。
循环轮转方式的程序简单,直观,开销小,可预测。循环轮转方式的软件系统只有一条执行流程和一个地址空间,
不需要任何之间的调度和切换,其程序的代码都是固定的,函数之间的调用关系也是明确的,整个系统的执行可预测。
循环轮转方式的缺点是程序必须按顺序执行,无法处理异步事件,缺乏并行处理的能力。缺乏硬件上的时间控制机制,
无法实现定时功能。
中断方式:
中断方式又称为前后台系统形式,系统在循环轮转方式的基础上增加了中断处理功能。
ISR中断服务程序负责处理异步时间,即前台程序,也称为时间处理程序。而后台程序是一个系统管理
调度程序,一般采用的是一个无限循环形式,负责掌管整个嵌入式系统软,硬件资源的分配,管理以及任务的调度。
后台程序也称为任务级程序,一般情形下,后台程序会检查每个任务是否具备运行条件,
通过一定的调度算法来完成相应的操作。而一些对实时性有要求的操作通常由中断服务程序来完成,
大多数的中断服务程序只做一些最基本的操作,如标记中断事件的发生等,其余的事情会延迟到后台程序去完成。
2:有操作系统的嵌入式软件
嵌入式操作系统在嵌入式系统中的广泛应用使得在应用软件开发时,程序员不是直接面对嵌入式硬件设备,
而是采用一些嵌入式软件开发环境,在操作系统的基础上编写程序。
在控制系统中,采用前后台系统体系结构的软件在遇到强干扰时,可能会使应用程序产生异常,
出错等从而造成系统的崩溃。而采用嵌入式操作系统管理的系统在遇到强干扰时,可能只会引起系统中的某一个进程被破坏,
但这可以通过系统的监控进程对其进行修复,系统具有自愈能力,不会造成系统崩溃。
嵌入式软件的结构层次:
最底层的是嵌入式硬件系统,包括嵌入式微处理器,存储器,键盘,LCD显示器等输入输出设备。
硬件层之上的是设备驱动层,他负责与硬件直接打交道,并为操作系统层软件提供所需的驱动支持。
操作系统层可以分为基本部分和扩展部分,基本部分是操作系统的核心,
负责整个系统的任务调度,存储管理,时钟管理,和中断管理等。
扩展部分为用户提供网络,文件系统,图形用户界面等。
操作系统的上一层是一些中间件。最上层是网络浏览器,电子邮件客户端等应用软件。
嵌入式系统的设备驱动:
嵌入式系统的设备驱动层用来完成嵌入式系统硬件设备所需的一些软件初始化和管理。
设备驱动层直接对硬件进行管理和控制,并为上层软件提供所需的驱动支持。
1:板级支持包
设备驱动层也称为BSP(板级支持包),在BSP中把所有与硬件相关的代码都封装起来,为操作系统提供一个虚拟的硬件平台,
操作系统运行在这个虚拟的硬件平台上。在BSP当中,使用一组定义好的编程接口来与BSP进行交互,
并通过BSP来访问真正的硬件。在嵌入式系统中,BSP类似于PC系统中的BIOS和驱动程序。
BSP把嵌入式操作系统和硬件平台隔离开来。通常BSP是针对某个特定的单板设计的,
系统都会提供相应的演示版本的BSP,BSP对于系统开发人员是开放的,
开发人员可以根据不同的硬件需求对其进行改动或二次开发。在实际开发一个嵌入式系统的时候,
通常可以找到一个与自己硬件系统相近的演示版本的BSP,并以此为基础进行修改和完善,
以适应不用单板的需求。BSP主要包括BootLoader和设备驱动程序两个方面的内容。
2:BootLoader:
Bootloader是在操作系统内核运行之前运行的一小段程序,通过这段程序,初始化硬件设备,建立内存空间的映射图,
从而将系统的软硬件环境设置到一个合适的状态,以便最终为调用操作系统内核做好准备。
BootLoader用来完成整个系统的加载启动任务。通常在系统上电或复位时,BootLoader程序从地址0x00000000处开始执行。
BootLoader的功能与嵌入式系统的硬件平台直接相关,不同的CPU体系结构和板级设备配置,BootLoader的功能不同。
一般来说,BootLoader主要包括片级初始化,板级初始化和加载内核等基本功能。
片级初始化:
片级初始化是一个纯硬件的初始化过程,把微处理器从上电时的默认状态逐步设置成系统所要求的工作状态。
片级初始化主要完成设置微处理的核心寄存器和控制寄存器,微处理器的核心工作模式及其局部总线模式等初始化。
板级初始化:
板级初始化是一个同时包含有软件和硬件在内的初始化过程,
通过正确地设置各种寄存器的内容来完成微处理器以外的其他硬件设备的初始化。
如初始化LED显示设备,定时器,串口通信和内存控制器,建立内存空间的地址映射,
设置中断控制寄存器和某些软件的数据结构和参数等。
加载内核:
将操作系统和应用程序的映像从Flash存储器复制到系统的内存当中,然后跳转到系统内核的第一条指令处继续执行。
3:设备驱动程序:
在一个嵌入式系统中,可以没有操作系统,但设备驱动程序是必不可少的。
设备驱动程序是一组库函数,用来对硬件进行初始化和管理,并向上层软件提供访问接口。
不同功能的硬件设备,他们的设备驱动程序是不同的。但大多数的设备驱动程序都具有硬件启动,
硬件关闭,硬件停用,硬件启用,读操作,写操作等基本功能。
设备驱动程序通常可以完成一些特定的功能,这些功能一般采用函数的形式来实现,
这些函数有分层结构和混合结构两种组织结构形式。
分层结构:
设备驱动程序中的函数分为硬件接口和调用接口两种类型,硬件接口直接跟硬件打交道,直接去操作和控制硬件设备。
调用接口不直接与硬件打交道,他们调用硬件接口当中的函数,与上层软件如操作系统中间件和应用软件打交道。
分层结构把所有与硬件有关的细节都封装在硬件接口当中,在硬件升级时,只需要改动硬件接口当中的函数即可。
混合结构:
上层接口和硬件接口的函数是混在一起的,相互调用,之间没有明确的层次关系。
嵌入式中间件:
中间件是一种软件平台技术,是指不包括操作系统内核,设备驱动程序和应用软件在内的所有系统软件。
嵌入式中间件把原本属于应用软件层的一些通用的功能模块抽取出来,形成独立的一层软件,
为应用软件提供一个灵活,安全移植性好的平台。
嵌入式中间件可以分为消息中间件,对象中间件,远程过程调用等不同的类型。
一些公司可提供嵌入式中间件集成解决方案,如Sun公司的嵌入式Java
嵌入式操作系统基础:
嵌入式系统中工作的操作系统称为EOS,EOS的基本功能主要体现在以下两个方面
1:构成一个易于编程的虚拟机平台
EOS构成一个虚拟机平台,EOS把底层的硬件细节封装起来,
为运行在它上面的软件如中间件软件和各种应用软件提供了一个抽象的编程接口。
软件开发在这个编程接口上进行,而不直接与硬件层打交道。
EOS所提供的变成接口实际上就是操作系统对外提供的系统调用函数。
2:系统资源的管理者
EOS是一个系统资源的管理者,负责管理系统当中的各重软硬件资源,
如处理器,内存,各种I/O设备,文件和数据等,使得整个系统能够高效,可靠的运转。
按响应时间分类的EOS:
按照系统对响应时间的敏感程度,EOS可以分为RTOS和非实时操作系统。
RTOS对响应时间有非常严格的要求,当某一个外部事件或请求发生时,
相应的任务必须在规定的时间内完成相应的处理。RTOS可以分为硬实时和软实时两种情况。
硬实时系统:
硬实时系统对响应时间有严格的要求,如果响应时间不能满足可能引起系统的崩溃或致命错误。
软实时系统:
软实时系统对响应时间有要求,如果响应时间不能满足,将需要支付能够接受的额外代价。
非实时系统对响应时间没有严格的要求,各个进程分享处理器,以获得各自所需的运行时间。
按软件结构分类的EOS:
单体结构:
单体结构是一种常见的组织结构,嵌入式linux操作,uc/os-II和PDOS都属于单体内核系统。
在单体结构的操作系统中,中间件和设备驱动程序通常就集成在系统内核当中,
整个系统通常只有一个可执行文件,里面包含了所有的功能组件。
单体结构的操作系统由一组功能模块组成,系统的各个模块之间可以相互调用,通信开销小,
系统高度集成和相互关联,系统剪裁,修改调试不方便。
分层结构:
采用分层结构的操作系统内部分为若干个层次,各个层次之间的调用关系是单向的,
即某一层次上的代码只能调用比它低层的代码。分层结构要求在每个层次上都要提供一组API接口函数,
增加了系统的额外开销。但系统的开发和维护较为简单,典型的代表有MS-DOS,其结构就是一个有代表性的,
组织良好的分层结构。
微内核结构:
微内核结构把操作系统的大部分功能都剥离出去,在内核中只保留最核心的功能单元如进程管理和存储管理,
大部分的系统功能都位于内核之外,例如将所有的设备驱动程序都置于内核之外。在微内核操作系统中
大部分的系统功能被放置在内核之外,客户单元和服务器的内存地址空间是相互独立的,系统具有更高的安全性。
新的功能组件也可以被动态的添加进来,扩展,调试,移植方便。
在微内核操作系统中,核内组件与核外组件之间的通信方式是消息传递,而不是直接的函数调用,运行速度可能会慢一些。
另外由于他们的内存地址空间是相互独立的,在切换的时候,也会增加额外的开销。VxWorks,OS-9等EOS都是采用微内核结构。
常见嵌入式操作系统:
VxWorks:
VxWorks采用基于微内核的体系结构,整个系统由四百多个相对独立,短小精炼的目标模块组成,
用户可以根据自己的需要选择合适的模块进行裁剪和配置VxWorks采用GUN类型编译器和调试器,
专有的API函数,支持x86,MIPS,ARM等主流的32位处理器。
VxWroks主要包含有实时微内核Wind,I/O处理系统,文件系统,网络处理模块,虚拟内存模块VxVMI,
板级支持包BSP等功能模块。实时微内核Wind包括基于优先级的任务调度,任务间的通信,同步和互斥,中断处理,
定时器和内存管理机制等功能。
嵌入式Linux:
嵌入式Linux是指对标准linux进行小型化剪裁处理后,可固化在存储器或单片机中,
适合于特定嵌入式应用场合的专用linux操作系统。常见的有uclinux,RT-linux,hard hat linux等
具有高性能,可裁剪的内核,其独特的模块机制使用户可以根据自己的需要,实时地将某些模块插入或移除内核。
适合于嵌入式系统的小型化的需要。
具有完善的网络通信和文件管理机制,支持所有标准的Internet网络协议,支持ext2,fat16,fat32,romfs等文件系统。
可提供完整的工具链,能够方便地实现从操作系统到应用软件各个级别的调试。
嵌入式Linux是开放源代码的自由操作系统,用户可以根据自己的应用需要方便的对内核进行修改和优化。
uclinux针对没有MMU的微处理器,RT-linux是最早实现硬实时支持的linux版本,hard hat linux是一个嵌入式实时系统,
可以针对硬件环境进行配置,以获得最佳的性能和最小的容量。
WinCE:
WinCE是一个基于优先级的多任务嵌入式操作系统,提供了256个优先级别,基本内核需要至少200KB,支持Win32API子集,
支持多种用户界面硬件,支持多种串行和网络通信技术。WinCE不是一个硬实时系统。
WinCE主要包含内核模块,内核系统调用和接口模块,文件系统模块,图形窗口和事件子系统模块和通信模块五个功能模块。
uc/os-II:
uc/os-II是一种免费,开放源代码,结构小乔,基于可抢占优先级调度的实时操作系统,其内核提供任务调度和管理,
事件管理,任务间同步与通信,内存管理和中断服务功能等。
uc/os-II内核在2kb-10kb数量级,具有执行效率高,占用空间小,实时性能优良和可扩展醒强等特点,
主要面向中小型嵌入式系统。uc/os-II内核提供最基本的系统服务,例如信号量,邮箱,消息队列,内存管理,中断管理等。
uc/os-II内核本身并不支持文件系统,但它具有良好的扩展性能,可以根据需要自行假如。
嵌入式系统的任务管理:
单道程序设计和多道程序设计
单道程序设计类型:
采用单道程序设计的操作系统在任何时候只能有一个程序在运行。当多个程序需要运行时,只能一个接一个的执行。
多道程序设计类型:
采用多道程序设计的操作系统允许多个程序同时存在并运行,采用多道程序技术可以有效提高系统资源的利用率。
当一个程序正在访问i/o时,会主动将CPU交出来,让另一个程序去运行。i/o和cpu的使用是并行进行的,
在总执行时间上要明显少于单道程序系统。
进程,线程和任务:
进程:
进程是在描述多道程序设计系统中并发活动过程引入的一个概念。进程和程序是两个既有联系又有区别的概念。
一个程序主要由代码和数据两部分内容组成。而进程是正在执行的程序,它是由程序和该程序的运行上下文两部分内容组成。
程序是静态的而进程是一个动态的,变化的。进程和程序也不是一一对应的。
一个进程通常包含有以下几个方面的内容:
相应的程序:进程是一个正在执行的程序,有相应程序的代码和数据。
CPU上下文:程序运行时,CPU中含有PC,PSW(程序状态字),通用寄存器,栈指针等各种寄存器的当前值内容。
一组系统资源:包括操作系统用来管理进程的数据结构,进程的内存地址空间,进程正在使用的文件等。
线程:
线程是一个比进程更小的能独立运行的基本单位。所谓的线程就是进程当中的一条执行流程。
从资源组合角度来看,进程把一组相关的资源组合起来,构成了一个资源平台,其中包括运行上下文,
内存地址空间,打开的文件等。
从程序运行的角度看,进程就是一个正在运行的程序,可以把进程看成是程序代码在这个资源平台上的一条执行流程(线程).
也就是可以认为进程等于线程加上资源平台。
在一个进程中,或者说在一个资源平台上,可以同时存在多个线程。可以用线程来作为CPU的基本调度单位,
使得各个线程之间可以并发执行。对于同一进程当中的各个线程来说,运行在相同的资源平台上,可以共享该进程的大部分
资源如内存地址空间,代码,数据,文件等。但也有一小部分资源是不能共享的如CPU运行上下文和栈。
任务:
在一些嵌入式系统中,把能够独立运行的实体称为任务。并没有进程或线程这两个概念。
在任务的创建过程需要定义的主要参数有任务的优先级,栈空间的大小和函数名。任务具有独立的优先级和栈空间,
CPU上下文一般是存在栈空间中,对于不同的任务,他们也能够访问相同的全局变量,在这些任务之间,
可以方便地直接地去使用共享的内存,而不需要经过系统内核来进行通信。
通常认为,在嵌入式操作系统中"任务"就是线程,如在VxWorks,uc/os-II,嵌入式linux等嵌入式操作系统中。
任务的层次结构:
在多道程序的嵌入式系统中,同时存在着多个任务。嵌入式内核启动时,只有一个任务存在,
然后由该任务派生出其他所有任务,这些任务采用层次结构,存在着父子关系。
任务的创建和终止:
任务的创建:在一个嵌入式操作系统中,在系统初始化,任务运行过程中,人机交互等过程中都可以创建任务。
在系统初始化时,一般都会创建系统与用户进行交互的一些前台任务和以及完成键盘扫描,系统状态检测,
时间统计等一些特定功能的后台任务。在任务运行过程中,也能够使用相应的系统调用来创建新的任务,
以帮助它完成自己的工作。
任务的终止:
当一个任务完成了所有的工作,需要结束运行,提出退出要求,称为正常退出。
当一个任务在执行过程中,出现了致命错误,系统中止该任务的运行,强制让该任务退出,称为错误退出。
任务的状态:
在多道程序系统中,任务是独立运行的实体,需要竞争系统资源,而任务所拥有的资源是在不断变化中的,
使得任务的状态也在不断的变化。一般来说,任务具有运行,就绪,和阻塞三种基本状态。
任务在运行状态时占有CPU并在CPU上运行,在任何一个时刻,处于运行状态的任务个数必须小于或等于CPU的数据。
当一个任务已具备运行条件,但由于CPU正在运行其他的任务,暂时不能运行该任务时就称为就绪状态,
当把CPU分给该任务,它就能立刻执行。
任务因为正在等待某种事件的发生而暂时不能运行称为阻塞状态,也叫等待状态。
此时,即使CPU已经空闲下来了,该任务也还是不能运行。
任务控制块:
TCB(任务控制块)是在操作 系统中用来描述和管理一个任务的数据结构。
通过对各个任务的TCB的操作来实现任务管理,利用TCB这个数据结构可以描述任务的基本情况,以及它的运行变化过程。
可以吧TCB看成是任务存在的唯一标识。
当需要创建一个新的任务时,就为它生成一个TCB,并初始化这个TCB的内容。
当需要终止一个任务的时候,只要回收它的TCB即可。
TCB主要包括任务的管理信息,CPU上下文信息,资源管理信息等内容。
任务的管理信息:
任务的管理信息包括任务的标识ID,任务的状态,任务的优先级,任务的调度信息,任务的时间统计信息,各种队列指针等。
CPU上下文信息:
CPU上下文信息包括通用寄存器,PC寄存器,程序状态字,栈指针等各种CPU寄存器的当前值,实际的嵌入式系统中,
CPU上下文信息不一定直接放在TCB,而是放在任务的栈当中,可以通过相应的栈指针来访问。
资源管理信息:
在操作系统中,任务表示的是进程,则还需要资源管理刚面的信息,如段表地址,页表地址等存储管理方面的信息。
根目录,文件描述字等管理信息。
任务切换:
任务切换是指一个任务正在CPU上运行,由于一些原因,系统需要调度另一个任务去运行,
那么这时就需要进行把当前任务的运行上下文保存起来,并设置新任务的上下文。
任务切换基本步骤:
将处理器的运行上下文保存在当前任务的TCB中。
更新当前任务的状态,从运行状态变为就绪或阻塞状态。
按照一定的策略,从所有就绪的任务中选择一个运行。
修改新任务的状态,从就绪态变为运行状态。
根据新任务的TCB内容,恢复它的上下文环境。
任务队列:
在一个多任务的操作系统中,各个任务的状态是经常变化的,有时处于就绪状态,有时又处于阻塞状态。
通常采用任务队列的方式来组织它的所有任务。以提高管理效率。
操作系统用一组队列来标示系统当中所有任务的当前状态。例如处于运行状态的所有任务构成了运行队列,
处于就绪的状态的所有任务构成了就绪队列,
而对于处于阻塞状态的任务,则要根据它们阻塞的原因,分别构成相应的阻塞队列。
对于系统当中的每一个任务,根据它的状态把他们的TCB加入到相应的队列当中去。
如果一个任务的状态发生变化,就把他的TCB从一个状态队列中脱离出来加入到另一个队列当中去。
任务的调度:
在多道程序操作系统中,当有两个或多个任务同时处于就绪状态时,而系统中只有一个CPU时并且处于空闲状态。
就会出现多个任务同时去竞争这个CPU,通常利用调度器选择就绪队列中的那些任务中的一个去运行,
调度器是CPU这个资源的管理者。
一般来说,在一个新的任务创建时,在一个任务运行结束时,在一个任务由于i/o操作,信号量或其他原因被阻塞时,
在一个i/o中断发生时,在一个时钟中断发生时这五种调度时机都可能会发生任务的调度。
任务的调度存在可抢占调度和不可抢占调度两种调度方式。
可抢占调度方式中,当一个任务正在运行时,出现调度时机当中的情况时,都有可能会发生调度。
调度程序可以去打断当前运行的任务,并让另一个任务开始运行。实时操作系统大都采用可抢占的调度方式。
不可抢占调度方式中,一个任务长时间地占用着CPU,系统也不会强制中止它。
当出现新任务创建,任务运行结束以及任务被阻塞时,有可能发生任务调度。
而对于发生的各种中断并不会去调用调度程序,而是在中断处理完成后,又回到刚才被打断的任务中去执行。
在嵌入式操作系统中,存在着许多的调度算法,每一种算法都有各自的优点和缺点。
可以根据响应时间,周转时间,调度开销,公平性,均衡性,吞吐量等指标来评价一个调度算法的好坏。
常见的调度算法:
先来先服务算法FCFS:
一种最简单的调度算法。FCFS的基本思想就是按照任务到达的先后次序来进行调度,它是一种不可抢占的调度方式。
也称FIFO算法。
短作业优先算法SJF:
抢占和不可抢占两种实现方式。
不可抢占方式中只有当前任务运行完毕或者是被阻塞时才会让出CPU进行新的调度。
而在可抢占方式中,当前任务正在运行的时候,如果来了一个比他执行时间更短的任务,
而且他的运行时间要小于当前正在运行的任务的剩余时间,
那么这个新任务就会抢占CPU去运行。这种方法也称为SRTF(最短剩余时间优先算法)
时间片轮转算法RR:
RR算法中,把系统当中的所有就绪任务按照先来先服务的原则进行排列,然后再每次调度的时候,
处理器分派给队列当中的第一个任务一小段CPU执行时间(时间片),当这个时间片结束的时候,
如果任务还没有执行完,就会发生是时钟中断,调度器将暂停当前任务的执行,并把这份任务送到就绪队列的末尾,
然后再执行当前的队列的第一个任务。如果第一个任务在分配给它的时间片结束前就已经运行结束了或者是被阻塞了,
那么他就会立刻让出CPU给其他任务。
采用RR算法,各个就绪任务平均地分配CPU使用时间。
优先级算法:
优先级调度算法中,给每一个任务都设置一个优先级,
然后再任务调度的时候在所有处于就绪状态的任务中选择优先级最高的那个任务去运行。
优先级算法可以分为可抢占和不可抢占方式。可抢占方式中,当一个任务正在运行时,如果这时候来了一个新的任务,
其优先级更高,则立即抢占CPU去运行这个新任务。而不可抢占方式则是需要等当前任务运行完后再决定。
可采用静态和动态方式来确定任务的优先级。静态优先级方式根据任务的类型或重要性,
在创建任务的时候就确定任务的优先级并且一直保持到任务结束。
动态优先级方式在创建任务的时候确定任务优先级,但是该优先级可以在任务运行过程中动态的改变,
以便或得更好的调度性能。
动态优先级方式可以克服静态优先级方式中高优先级的任务一直占用着CPU,
而那些低优先级的任务可能长时间地得不到CPU的情况。
通常在优先级算法中,对于优先级相同的两个任务,通常是把任务按照不同的优先级进行分组,
然后不同组之间的任务切换使用优先级算法,而在用一个组中的任务调度使用时间片轮转法。
实时系统调度:
实时系统的调度追求的是实时性,RTOS调度器要让每个任务都在其最终时间期限之前完成,
而各任务之间的公平性并不是最重要的指标。RTOS调度器多采用基于优先级的可抢占调度算法。
单调速率调度算法RMS:一种静态优先级调度算法
最早期限优先算法:一种动态优先级调度算法
嵌入式系统的存储管理:
嵌入式存储管理方式的特点:
在实时系统中,存储管理方法比较简单,甚至不提供存储管理功能。而对于一些实时性要求不高,可靠性要求比较高,
比较复杂的系统中需要实现对操作系统或任务的保护,在存储管理方式上就比较复杂。
嵌入式微处理器中,MMU提供了一种内存保护的硬件机制。内存保护用来防止地址越界和防止操作越权。
采用内存保护机制的每个应用程序都有自己的独立地址空间。当一个程序需要访问内存的某个单元时,
由硬件检查该地址的合法性。对于多个应用程序共享的某块存储区域,每个应用程序都有自己的访问权限,
如果违反了权限规则。则要进行越权操作处理。
操作系统通常利用MMU来实现系统内核与应用程序的隔离,以及应用程序与应用程序之间的隔离。
防止应用程序去破坏操作系统和其他应用程序的代码和数据,防止应用程序对硬件的直接访问。
MMU通常只在一些对安全性和可靠性的要求比较高,系统比较复杂的嵌入式系统中存在
存储管理的实模式和保护模式:
实模式存储管理:
实模式存储管理中,系统不使用MMU,不划分系统空间和用户空间,整个系统只有一个地址空间,即物理内存地址空间。
应用程序和系统程序都能直接对所有的内存单元进行随意的访问,无需进行地址映射。
操作系统的内核与外围应用程序在编译连接后,两者通常被集成在同一个系统文件中。
系统中的"任务"或"进程"均是内核线程,只有运行上下文和栈是独享的,其他资源都是共享的。
在实模式存储管理方式中,系统的内存地址空间一般可以分为text,data,bss,堆,栈五个部分。
.text(代码段)用来存放操作系统和应用程序的所有代码
.data(数据段)用来存放操作系统和应用程序当中所有带有初始值的全局变量。
.bss(未初始化数据段)用来存放操作系统和应用程序当中所有未带初始值的全局变量。
堆:为动态分配的内存空间,在系统运行时,可以通过类似于malloc/free之类的函数来申请或释放一段连续的内存空间。
栈:用来保存运行上下文以及函数调用时的局部变量和运行参数。
对于实时系统来说,实模式方案简单,存储管理的开销确定,比较适合于规模较小,简单和实时性要求较高的系统。
其缺点就是没有存储保护,安全性差。
保护模式存储管理:
在保护模式存储管理方式中,微处理器必须具有MMU硬件并启用它。
在保护模式存储管理方式中,系统内核和用户程序有各自独立的地址空间,
操作系统和MMU共同完成逻辑地址到物理地址的映射。每个应用程序只能访问自己的地址空间,对于共享的内存区域,
也必须按照规定的权限来访问,具有存储保护功能。
保护模式存储管理方式的安全性和可靠性较好,适合于规模较大,较复杂和实时性要求不太高的系统。
地址映射:
把用户程序中的逻辑地址转换成为运行时由机器直接寻址的物理地址,这个过程就称为地址映射。
地址映射主要有静态地址映射和动态地址映射两种方式。
页式存储管理:
页式存储管理打破存储分配的连续性,一个程序的逻辑地址空间可以分布在若干个离散的内存块上,
以达到充分利用内存,提高内存利用率目的。
在页式存储管理方式中,一方面把物理内存划分为许多个固定大小的内存块,称为物理页面或页框。
另一方面,把逻辑地址空间也划分为大小相同的块,称为逻辑页面。
页面的大小为2^n,一般在512字到8Kb之间。当一个用户程序被装入内存时,
不是以整个程序为单位把它存放在一整块连续的区域中,而是以页面为单位来进行分配的。对于一个大小为N个页面的程序,
需要有N个空闲的物理页面,这些物理页面可以使不连续的。
在实现页式存储管理时,需要解决数据结构,内存的分配与回收,地址映射等问题。
数据结构:
页式存储管理中,最主要的数据有页表和物理页面两个。页表给出了逻辑页面号与内存中的物理页面号之间的对应关系。
物理页面表用来描述内存空间当中,各个物理页面的使用分配状况。
物理页面表可以采用位示图或空闲页面链表等方法来实现。
内存的分配和回收:
当一个任务到来时,需要可虑如何给他分配内存空间。当一个任务结束后,需要考虑如何回收它所占用的内存空间。
内存的分配与回收算法与物理页面表的实现方法是密切相关的。
当一个任务到来时,首先需要计算它所需要的页面N,查询是否还有N个空闲的物理页面,
如果有足够的空闲物理页面,则需要申请一个页表,其长度为N,并把页表的起始地址填入到该任务的任务控制块TCB中。
然后分配N个空闲的物理页面并编号,把他们的编号填入到页表中,建立逻辑页面与物理页面之间的对应关系,
并对刚刚被占用的那些物理页面进行标记。
当一个任务运行结束,释放了它所占用的内存空间后,需要对这些物理页面进行回收
地址映射:
在页式存储管理方式中,当一个任务被加载到内存后,连续的逻辑地址空间被划分为一个个的逻辑页面,
这些逻辑页面被装入到不同的物理页面中。在这种情况下,为了保证程序能够正确地运行,需要把程序中使用的逻辑地址
转换成内存访问时的物理地址,完成地址映射。
地址映射是以页面为单位进行的。在进行地址映射时,首先分析逻辑地址,对于给定的一个逻辑地址,
找到它所在的逻辑页面,以及他在页面内的偏移地址。然后进行页表查找,根据逻辑页面号,
从页表中找到它所对应的物理页面号,最后进行物理地址的合成,根据物理页面号以及页内偏移,最终确定物理地址。
要注意的是,采用页式存储管理方式,程序必须全部装入内存才能够运行。操作系统必须为每一个任务都维护一张页表。
开销比较大,当简单的页表结构不能满足应用程序的要求时必须设计出更复杂的页表结构,如多级页表结构,哈希页表结构等。
虚拟页式存储管理:
在操作系统的支持下,MMU可以提供虚拟存储功能,
即使一个任务所需的内存空间超过了系统所能提供的内存空间,也能够正常运行。
虚拟页式存储管理就是在页式存储管理的基础上,增加了请求调页和页面置换的功能。
在虚拟页式存储管理方式中,当一个用户程序需要掉入内存去运行时,不是将这份程序的所有页面都装入内存,
而是只装入部分的页面,就可以启动这个程序运行,在运行过程中,如果发现要执行的指令或者要访问
的数据不再内存当中时,就向系统发出缺页中断请求,然后系统在处理这个中断请求时,
就会将保存在外存中的相应页面调入内存,从而使该程序能继续运行。
系统在处理缺页中断时,需要调入新的页面,如果此时内存已满,就需要采用某种页面置换算法,从内存中选择某一个页面,
把它置换出去。常用的页面置换算法有:
最优页面置换算法,最近最久未使用算法,最不常用算法,先进先出算法和时钟页面置换算法。
采用虚拟页式存储管理方式,对于每一个页表项来说,除了需要逻辑页面号和与之相对应的物理页面号信息外,
还需要增加包括驻留位,保护位,修改位和访问位等信息。
输入/输出设备管理:
I/O编址:
一个I/O单元通常是由I/O设备本身和设备控制器两个部分组成。I/O设备负责与人,控制对象等打交道。
而设备控制器则负责完成I/O设备与主机之间的连接和通信。
在每一个设备控制器当中,都会有控制寄存器,状态寄存器和数据寄存器等一些寄存器用来与cpu进行通信。
通过往这些寄存器中写入不同的值,操作系统就可以命令I/O设备去执行数据发送与数据接收,打开与关闭设备等操作。
操作系统也可以通过读取这些寄存器的内容来了解这个I/O设备的当前状态。
被CPU访问的设备控制器寄存器主要采用I/O独立编址,内存映像和混合编址。
I/O独立编址:
在I/O独立编址方式中,给设备控制器中的每一个寄存器,分配一个唯一的I/O端口地址,
然后采用专门的I/O指令来对这些端口进行操作。这些端口所构成的地址空间是完全独立的,
与内存的地址空间没有任何关系,I/O设备不会去占用内存的地址空间。
而且在编写程序时,他们的指令形式是不一样的,很容易区分内存访问和I/O端口访问。
内存映像编址:
在内存映像编址方式中,把设备控制器当中的每一个寄存器都映射为一个普通的内存单元,
这些内存单元专用于I/O操作,而不能作为普通的内存单元来使用。端口地址空间与内存地址空间时统一编址的,
端口地址空间是内存地址空间的一部分。编程方便,无需专用的I/O指令。
混合编址:
混合编址就是把I/O独立编址和内存映像编址两种编址方法混合在一起。
对于设备控制器中的寄存器,采用I/O独立编址的方式,每一个寄存器都有一个独立的I/O端口地址。
对于I/O设备的数据缓冲区,则采用内存映像编址的方法,把I/O设备的数据缓冲区的地址与内存地址统一编址,
I/O设备的数据缓冲区的地址空间是内存地址空间的一部分。
I/O控制方式:
I/O设备的控制方式主要有程序循环检测,中断驱动和直接内存访问三种形式。
I/O软件:
为了管理好嵌入式系统中的各式各样的I/O设备,在I/O软件通常采用分层的体系结构,
一般来说,可以分为中断处理程序,I/O设备驱动程序,设备独立的I/O软件和用户控件的I/O软件四个层次。
其中低层软件是面向I/O硬件的,与I/O硬件特性密切相关,它把I/O硬件同上层的软件有效隔离开来。
而较高层的软件是面向用户的,为用户提供一个友好,清晰,统一的编程接口。
1:中断处理程序
中断处理程序与I/O设备驱动密切配合,用来完成特定的I/O操作。
当一个用户程序需要某种I/O服务时,它会去调用相应的系统函数,而这个函数又会去调用相应的I/O设备驱动程序。
然后在I/O设备驱动程序中启动I/O操作,并且被阻塞起来,直到这个I/O操作完成后,
将产生一个中断,并跳转到相应的中断处理程序。之后再中断处理程序中,将会唤醒被阻塞的I/O设备驱动程序。
在中断处理过程中,需要执行保存CPU的运行上下文,为中断服务子程序设置一个运行环境,
向中断控制器发出应答信号,执行相应的中断服务子程序等操作,需要一定的时间开销。
2:I/O设备驱动程序:
I/O设备驱动程序是直接对I/O设备进行控制的软件模块,接收并且去执行来自于上层I/O软件的请求。
上层的I/O软件通过这些抽象的函数接口与I/O设备驱动程序打交道,硬件设备的具体细节被封装在I/O设备驱动程序里面。
I/O设备驱动程序与具体的设备类型密切相关。每一个I/O设备都需要相应的I/O设备驱动程序,
而每一个设备驱动程序一般也只能处理一种类型的设备,因为对于不同类型的设备,他们的控制方式是不同的。
3:设备独立的I/O软件
设备独立的I/O软件位于设备驱动程序的上面,是系统内核的一部分,实现所有设备都需要的一些通用I/O功能,
并向用户级的软件提供一个统一的访问接口。设备独立的I/O软件主要完成设备驱动程序的管理与设备驱动程序的统一接口。
设备的命名,保护,缓冲技术,出错报告以及独占设备的分配和释放等功能。
I/O系统通常会提供一个统一的调用接口,包含了一些常用的设备操作,如设备初始化,打开,关闭设备。读写设备等。
设备驱动程序的管理通过驱动程序地址来实现。驱动程序地址表中存放了各个设备驱动程序的入口地址,
可以通过此表来实现设备驱动的动态安装与卸载。
在实现数据的I/O操作时,为了缓解CPU与外部设备之间速度不匹配的矛盾,提高资源的利用率,
可以在内存中开辟一个存储空间,作为缓冲区,即采用缓冲技术。当读取I/O设备数据时,不同去访问I/O外设,
直接到缓冲区中去查找。同样,在往I/O设备中写入数据时,可以先写到缓冲区中。
这样,I/O外设需要用到这些数据时,可以直接从缓冲区中去取。
缓冲技术可以分为单缓冲,双缓冲,多缓冲和环形缓冲。
4:用户空间I/O软件
大部分的I/O软件通常都包含在操作系统中,是操作系统的一部分,但也有一小部分的I/O软件,
如与用户程序进行连接的库函数和完全运行在用户空间当中的程序,他们运行在系统内核之外。称为用户空间的I/O软件。
与用户程序进行连接的库函数在运行时,例如调用的各种I/O库函数,
通常是把传给它们的参数再往下传递给相应的系统函数,然后由后者来完成时间的I/O操作。
Spooling(外围设备联机操作)技术是在多到系统中,一种处理独占设备的方法。
它可以把一个独占的设备转变为具有共享特征的虚拟设备,能够提供高速的虚拟I/O服务,实现对独占设备的共享,
从而提高设备的利用率。
在多道系统当中,对于一个独占的设备,专门利用Spooling程序来增强该设备的I/O功能。
Spooling程序负责与这个独占的I/O设备进行数据交换,完成实际的I/O操作。
同时,应用程序在进行I/O操作时,只同这个Spooling程序交换数据。
与Spooling程序当中的缓冲区打交道,从中读出数据或往里面写入数据,
而不是直接对实际的设备进行I/O操作,即实现虚拟的I/O操作。
阅读(909) | 评论(0) | 转发(0) |