操作系统-基础知识

一、操作系统的基本概念

1.定义

Operating System,OS:指控制和管理整个计算机系统的硬件与软件资源,合理的组织、调度计算机的工作与资源的分配,并且可以为用户和应用软件提供系统调用和运行环境的程序集合

2.特征

并发(Concurrence)

指两个或多个事件在同一时间间隔内发生。计算机系统中“同时”运行着多个程序,这些程序宏观上看是同时运行着的,而微观上看是交替运行的

共享(Sharing)

共享即资源共享,是指系统中的资源可供内存中多个并发执行的进程共同使用

互斥共享方式:系统中的某些资源,虽然可以提供给多个进程使用,但一个时间段内只允许一个进程访问该资源

同时共享方式:系统中的某些资源,允许一个时间段内由多个进程“同时”对它们进行访问

并发和共享互为存在条件

没有并发和共享,就谈不上虚拟和异步,因此并发和共享是操作系统的两个最基本的特征

虚拟(Virtual)

虚拟是指把一个物理实体变为若干个逻辑上的实体。物理实体是实际存在的,而逻辑上的实体是用户感受到的

异步(Asynchronism)

异步是指,在多道程序环境下,允许多个程序并发执行,但由于资源有限,进程的执行不是一贯到底的,而是走走停停,以不可预知的速度向前推进,这就是进程的异步性

3.发展和分类

手工操作阶段(1946-1950年)

这个阶段还没有操作系统

操作系统-基础知识_第1张图片

单道批处理系统(50年代末-60年代中)

引入脱机输入/输出技术(用外围控制机+磁带完成),并由监督程序(操作系统的雏形)负责从磁带上调入一道程序进入内存运行

多道批处理系统(60年代中-70年代中)

标志着操作系统的出现

操作系统-基础知识_第2张图片

分时操作系统(70年代中-至今)

多个用户分时共享同一台计算机,响应时间短,人机交互性好

操作系统对各个用户都是完全公平的,循环地为每个用户服务一个时间片,不区分任务的紧急性,所以缺点是不能优先处理一些紧急任务

时间片轮转的系统,其吞吐量和周转时间均不如批处理系统

时间片的选择很重要,若时间片大到让一个进程足以完成其全部工作,则这种算法退化为先来先服务算法;若时间片太小,则处理器在进程之间的转换工作太频繁,系统开销增大

实时操作系统

适于处理紧急任务,响应快,可靠性高,但资源利用率低

在实时操作系统的控制下,计算机系统接收到外部信号后及时进行处理,并且要在严格的时限内处理完事件。实时操作系统的主要特点是及时性和可靠性

硬实时操作系统:必须在绝对严格的规定时间内完成处理(如导弹控制系统、自动驾驶系统)

软实时操作系统:能接受偶尔的延时处理(如订票系统)

其他类型的操作系统

网络操作系统:伴随计算机网络的发展而诞生的,能把网络中各个计算机有机地结合起来,实现数据传送等功能,实现网络中各种资源的共享(如文件共享)和各台计算机之间的通信。如Windows NT就是一种典型的网络操作系统,网站服务器使用

分布式操作系统:主要特点是分布性和并行性。系统中的各台计算机地位相同,任何工作都可以分布在这些计算机上,由它们并行、协同完成这个任务

个人计算机操作系统:如Windows XP、MacOS等,此外还有嵌入式操作系统、智能手机操作系统(Android、iOS)

4.功能

  • 处理机管理:进程切换、进程调度、进程同步、进程通信
  • 存储器管理:内存分配、地址映射、内存保护、虚拟内存
  • 文件管理:目录管理、文件保护、文件存储空间管理
  • 设备管理:设备分配、缓冲管理、虚拟设备、统一设备驱动程序接口
  • 提供命令接口,包括联机命令接口(又称交互式命令接口,用户输入一条命令,系统跟着执行一条)、脱机命令接口(又称批处理命令接口,用户一次性输入多条命令,系统按序全部执行)
  • 提供程序接口:就是程序中的系统调用(也称广义指令)
  • 提供图形接口:图形界面GUI属于操作系统提供的非内核部分的功能,但也可以放入内核里(比如Windows NT)

二、操作系统的系统调用

1.系统调用的概念

UNIX中,write()这种函数叫系统调用封装函数,是系统级IO函数。它是对系统调用的封装,而编程语言提供的库函数或操作系统提供的API函数是对系统级IO函数的封装

系统调用(system call)是操作系统内核实现的对硬件操作的函数,然后向上层用户或应用软件提供的调用接口

系统调用是用户或上层应用程序使用操作系统及底层硬件的入口,是操作系统内核代码的入口

2.用户态到核心态的转换

每一个系统调用内都有一条软件中断(trap自陷)的代码(如int 80)

操作系统把中断作为用户态进入核心态的唯一方式,利用中断处理程序来实施各种检查,让上层应用只能按照操作系统规定的格式来使用系统

int80的中断描述符(其他中断描述符不一定)的DPL为3,所以能通过特权级检查

通过中断描述符找到中断处理程序的CS段选择子(此时CPL被置为0)和偏移地址,通过GDT+段选择子找到段描述符获得基址,再拼接上偏移地址就找到了中断处理程序入口,然后就开始执行系统调用的实现了

三、操作系统的结构

操作系统-基础知识_第3张图片

1.宏内核

  • 把所有功能模块作为一个紧密联系的整体编译链接,整体运行在核心态
  • 优点:性能好
  • 缺点:没有模块化,没有扩展性、没有移植性,代码高度耦合,一旦其中一个组件有漏洞,内核中所有的组件可能都会出问题,维护困难。开发一个新的功能也得重新编译、链接、安装内核。纯粹的宏内核已经没人用了,就算要追求性能也是用混合内核

宏内核提供内存分配功能的服务过程举例

  1. 应用程序调用内存分配的API函数
  2. 处理器切换到特权模式,开始运行内核代码
  3. 内核里的内存管理代码按照特定的算法,分配一块内存
  4. 把分配的内存块的首地址,返回给内存分配的API函数
  5. 内存分配的API函数返回首地址,处理器开始运行用户模式下的应用程序,得到了首地址并且可以使用这块内存了

2.微内核

  • 内核功能精简:仅仅只有进程调度、处理中断、内存空间映射、进程间通信等功能,与硬件相关的代码也放进内核
  • 服务进程:把实际的进程管理、内存管理、设备管理、文件管理等功能,做成一个个服务进程,服务进程运行在用户态。某个服务进程崩溃不会使整个系统崩溃
  • 消息传递机制:应用程序要请求相关服务,就向微内核发送一条与此服务对应的消息,微内核再把这条消息转发给相关的服务进程,接着服务进程会完成相关的服务,再由微内核转发返回
  • 微内核有三个显著特征:①机制与策略分离:机制放入内核,策略放入服务进程②基于CS模式③采用面向对象技术
  • 缺点:性能差
  • 优点:结构清晰利于协作开发、扩展性好、可移植性好。可以随时拿掉一个服务进程以减少系统功能,或者增加几个服务进程以增强系统功能

微内核提供内存分配功能的服务过程举例

  1. 应用程序发送内存分配的消息,这个发送消息的函数是微内核提供的,相当于系统API,微内核的API相当少,极端情况下仅需要两个,一个接收消息的 API 和一个发送消息的API
  2. 处理器切换到特权模式,开始运行内核代码
  3. 微内核代码让当前进程停止运行,并根据消息中的数据,确定消息发送给谁,分配内存的消息当然是发送给内存管理服务进程
  4. 内存管理服务进程收到消息,分配一块内存
  5. 内存管理服务进程,也会通过消息的形式返回分配内存块的地址给内核,然后继续等待下一条消息
  6. 微内核把包含内存块地址的消息返回给发送内存分配消息的应用程序
  7. 处理器开始运行用户模式下的应用程序,应用程序就得到了一块内存的首地址,并且可以使用这块内存了

3.混合内核

综合了宏内核与微内核优点的方案

4.分层结构

单向依赖:最底层是硬件,最高层是用户接口,每层可调用紧邻的更低一层的功能

  • 优点:便于调试(从底层往上层一步步调试)、可拓展(增、改、删层时,只要不改变层间接口,就不会影响其他层)
  • 缺点:合理定义划分各层功能比较困难、效率较差(层层调用增加了额外开销)

操作系统-基础知识_第4张图片

5.模块化结构

模块之间独立,各模块间通过接口通信

操作系统-基础知识_第5张图片

6.外核

  • 内核管进程调度、进程通信等功能,外核负责为用户进程分配未经抽象的硬件资源,且外核负责保证资源使用安全
  • 优点:外核减少了硬件资源的“虚拟映射层”,提高了效率
  • 缺点:降低了系统的一致性,使系统更复杂

操作系统-基础知识_第6张图片

四、操作系统的启动过程

操作系统-基础知识_第7张图片

操作系统-基础知识_第8张图片

BIOS是针对具体主板设计的,与操作系统无关。BIOS中包含了各种基本设备的驱动程序,通过指向BIOS,这些基本驱动程序以中断服务程序的形式被加载到内存中,以提供基本IO系统调用。一旦进入保护模式,就不再使用BIOS

操作系统-基础知识_第9张图片

加电后PC被初始化为0xFFFF0(具体来说,CS置0xFFFF,IP置0x0000),CPU启动(开始取指执行),这个入口地址处是个跳转指令,跳转到0xFE05B地址处执行。此时执行代码的功能是:先硬件自检(Power-on Self Test)、初始化,再建立BIOS中断向量表和填写相应中断例程。在这之后,BIOS调用中断服务例程会读取存储设备的0盘0道1扇区的内容(共512B),如果验证了末尾两个字节是0x55和0xaa,那么BIOS就找到了主引导记录(启动区),然后就把这512B的内容从磁盘加载到内存0x7c00的位置,之后就是一条跳转指令,跳到0x7c00处执行。此时,BIOS的工作就完成了

操作系统-基础知识_第10张图片

主引导记录(Linux0.11的bootsect.s为例)被加载到内存0x7c00处后,然后自己把自己移动到内存0x90000处(读入操作系统核心代码腾出空间),然后将ds和cs设置为了0x9000,方便之后程序访问代码和数据。并且,将栈顶地址ss:sp设置在了离代码的位置0x9000足够遥远的 0x9FF00,保证栈向下发展不会轻易覆盖掉已有的代码。再然后bootsect.s继续读入操作系统的setup.s文件,从硬盘的第2个扇区开始,把数据加载到内存0x90200处,共加载4个扇区,再然后,把操作系统的核心system模块从硬盘第6个扇区开始往后的240个扇区,加载到内存0x10000处。至此,整个操作系统的全部代码,就已经全部从硬盘加载到内存中了。然后又通过一个段间跳转指令jmpi0,0x9020,跳转到0x90200处,就是硬盘第二个扇区开始处的内容(setup.s)

操作系统-基础知识_第11张图片

操作系统-基础知识_第12张图片

setup做三件事,先获取(使用BIOS中断)硬件(内存、硬盘、显卡)的一些信息存储在0x90000处开始的地方(具体位置如下图),接下来把内存地址0x10000处开始往后一直到 0x90000的内容,复制到内存的最开始的0位置,最后,就要从实模式转变为保护模式(打开A20地址线,初始化GDT表,设置GDTR寄存器,然后将CR0寄存器第0位置1,就从实模式切换到保护模式(启动保护模式的实质是启动MMU来完成运行时重定位)了,然后进行长跳转(跳转到0地址执行))

操作系统-基础知识_第13张图片

操作系统-基础知识_第14张图片

此时0地址处存储着操作系统全部核心代码(如下图),在进入C语言写的main.c之前,要先执行head.s。head.s做三件事:设置中断表和IDTR寄存器(将system从0x10000挪到0地址处时,BIOS中断就没法使用了,此时IDT表项没实在的内容,等到后面给各个模块初始化时,才会设置相应例程的入口地址到各个表项中)、重新设置GDT表和GDTR寄存器(这里重新设置在head程序中如第二幅图,这块内存不会被其他程序用到并且覆盖,并且最后还预留了252项的空间,这些空间后面会用来放置任务状态段描述符TSS和局部描述符表LDT)、最后设置页表(页表存放在0地址处开始的5个长度为4kb的内存中,覆盖了开头的已经执行过的system代码,四个页目录项将前16M的线性地址空间与16M的物理地址空间一一对应起来),设置页表寄存器CR3,设置CR0的最高位为1(启动分页机制),然后跳转到main函数执行(此时内存如图1.29),main是绝对不会返回的,否则就会到一个死循环(死机)

操作系统-基础知识_第15张图片

操作系统-基础知识_第16张图片

操作系统-基础知识_第17张图片

操作系统-基础知识_第18张图片

main函数里是各个模块的初始化函数;再之后的fork函数会创建一个新的进程,最终会启动一个shell程序与用户进行交互,这标志着操作系统建立完毕,达到了一个用户可用的状态

你可能感兴趣的:(计算机基础,linux,笔记,学习方法)