操作系统如何启动:一步步详解

发表时间: 2024-05-11 17:35

首先我们知道,计算机本身就是一堆的硬件,而这堆硬件当中最核心的就是我们的CPU和所谓的存储器设备。为了能够实现计算机获得数据,实现数据的输入输出等等,他需要输入设备和输出设备两种,但是对于计算机系统来讲,核心只是运算器和控制器即CPU和我们存储设备。

一台计算机在某一时刻只能运行一个程序,但是计算机的计算能力很强,一个程序所需要运行的程序内容所需要占据所有时间可能会不是特别的长,由于我们为了能够尽可能的利用计算机的计算能力,于是需要将计算机同时运行多个程序,每一个程序在运行起来以后需要一个协调器,这个协调程序叫操作系统(operating system)。我们这里把它称为操作系统是不合适的,因为我们所理解中的操作系统可能会包含了很多外围的其他程序,所以此处我们把它称为叫内核更合适一点。后面我们把它称为内核,叫做kernel,是操作系统的核心。内核本身就负责管理硬件资源,并且将硬件资源虚拟成其他样子,提供给上层所需要运行的应用程序。

为什么需要这样去做呢,如果程序直接运行在硬件上,那么这个程序本身就可以控制硬件的各种属性,其他程序也直接运行在硬件上的时候,这些程序彼此之间可能会产生干扰,一个恶意的运营程序可能会导致其他程序通通退出,所以我们需要一个统一的资源管理者,而且任何应用程序要想能够使用硬件必须要通过内核来完成。

而内核也不会让程序直接访问硬件,它是通过将硬件所提供的运行能力,通过一个一个的叫做系统调用来实现的,这是内核所提供的非常重要的一个功能,我们把他说叫system call(系统调用),这个功能是非常底层的实现。

计算机层次结构

如果程序员根据系统调用来编程,会非常麻烦和繁琐,而且许多程序之间的功能是相同的。举个简单例子,比如说我们的word需要打印,excel也需要打印,由于系统调用本身非常底层,如果不把这些功能做成公用的话。这也就意味着,word的需要自己开发一个打印模块,excel同时也需要一个打印模块,在我们计算机上大量的功能是重复的,这种重复势必会额外占用空间,所以从资源的组织角度来讲也是不合理的。

我们操作系统除了提供内核之外,通常还需要将自己的内核所提供的一些系统调用输出出来,而这种输出是通过较为高层一点的调用接口来实现,这种接口我们把它叫做库 library(学过软件开发的人应该知道,比如java编程中的提供各种功能的jar包)。对于库本身也是一个应用程序,只不过这个应用程序没有程序的执行入口,它是不能自我独立运行的,只能被其他程序调用的时候才能执行,这就是我们把它称为叫库的原因。

库存在的执行环境就是被调用,也就意味着我们的调用可能不仅仅调用系统内核所提供的功能,也可能会调用库所提供的功能,这里可以想一个问题,如果一个程序员在编程的时候不使用库,直接在内核上进行编程可不可以呢?答案是可以的,只不过这比较麻烦而已,所以我的调用除了系统调用之外,还有库调用(library call),这点要清楚,这也是简称为lib的一个主要原因。

库本身对一个操作系统而言,我们把它称为应用编程接口API,全称叫做application program interface(应用编程接口),应用编程接口他也是程序,所以对windows而言和对于linux而言甚至UNIX而言,每一个不同的系统它的程序员在开发库的时候,所实现的功能以及它的内部实现细节可能是各不相同的那这也就意味着,如果说某个人利用windows的库要用进行编程,那么这个程序拿到linux上未必能运行,因为他们库不一样,当然库的内部实现细节不一样,但是如果他的调用接口是一样的,那么这个程序能不能运行呢?答案是没有问题的,这是我们的库。

在库的上层就是各个应用程序了,这个应用程序很可能直接进行在系统调用(内核)上,也有可能是通过我们的库调用来完成,使用库库用编程起来可能会更简单,但如果使用内核调用,它的执行效率可能会更高,因为至少不会通过库来完成了,而且所获得的操作权限也可能会更大,因此一些高级的黑客们,他们可能会直接使用系统调用来实现,编程甚至于直接利用硬件特性编程。我们不扯那么远,但无论如何无论有多少个应用程序,这些应用程序在操作系统启动的时候,这个程序未必会运行起来,只不过说操作系统一启动这就意味着,这些程序已经具备了运行条件,或者说已经有了运行环境。但是它并没有运行,什么时候运行,通常我们启动一个程序的方式可能有多种。

比如说我们让操作系统一启动之后,这个程序就自动能够启动起来,大家有没有留意过windows,你装完以后一个干净的系统,然后点一下你的进程管理器,也会发现后台运行有很多进程对不对,这些进程是随系统的启动而启动的,这些进程有些我们把它称为服务。为什么称呼叫服务呢?因为你的操作系统自身运行,为了提供一个完整的能力或者为了提供一个完整意义上的操作系统,它就必须要运行起来,才能让我们系统能够完整的提供一个基本的功能,那这种我们把它称为叫后台服务。

而且是随系统自动启动的,当然也有一些是我们按需启动,比如我们希望编译编辑一个word文档的时候,你才有必要启动word,如果你启动window系统时,word就自动启动没有太大任何意义,所以有时候我们需要手动启动,而这种程序,我们通常把它称为叫交互式程序,为什么是交互式呢,因为他本身就是个编辑器,需要用户不停的去编辑些内容的,所以交互式程序是需要跟用户进行交互的。

对于用户来讲,我们使用计算机无非就是输入设备和输出设备,输入设备比如键盘、鼠标,输出设备是我们的显示器等等。现在我们考虑这样的一个问题,我们键敲一下键盘之后,输入的信息首先到达CPU接收,CPU发现你敲下键盘以后,CPU并不知道敲键盘这个信息意味着什么,比如说你按一下CTRL+C,它是不是复制粘贴,还是说你随意按的一个键呢,为什么CTRL+C就是复制呢,对于某些编译器来说,我们必须要把这个键盘的键解析为对应应用程序所能够理解的功能,能够跟硬件交互的只有内核是,所以CPU在获得这个信息以后,他是首先通知内核来进行处理,而不是直接说我交给word,所以这个时候,内核必须要能够在CPU上运行起来,并且接着去处理这么一个信号。

当然内核知道这个程序是由哪个进程发起来的,因为整个系统资源的监控,包括上层所运营的应用程序监控,都是由内核来完成的,哪个进程处于当前焦点进程,而负责接收这样一个快捷键或者这样一个键的组合,由内核再转交给应用程序,这就是一个应用程序的执行过程。

其实操作系统本身也是一个程序,他也需要运行起来,既然需要运行它就需要有指令和数据,而指令和数据是放在内存当中的,即我们之前提到的存储器当中。也就是说在我们的存储器当中既有内核,也有其他的应应程序。如果说一个恶意的应应程序能够直接访问内核,直接跟内核进行交互,能够直接去修改内核中的某些数据。那么系统的稳定性将无从得到保证,所以我们必须有一种机制能够将应用程序和内核隔离开来。

通常情况下比如说像因特尔这类处理器会提供所谓的保护机制或者叫保护模式。一般我们内存分为4个级别,用同心圆的四个环来表示,最内层我们称为叫0级别或者叫ring0。ring0是指CPU的运行级别,ring0是最高级别,ring1次之,ring2更次之…… 拿Linux+x86来说, 操作系统(内核)的代码运行在最高运行级别ring0上,可以使用特权指令,控制中断、修改页表、访问设备等等。 应用程序的代码运行在最低运行级别上ring3上,不能做受控操作。如果要做,比如要访问磁盘,写文件,那就要通过执行系统调用(函数),执行系统调用的时候,CPU的运行级别会发生从ring3到ring0的切换,并跳转到系统调用对应的内核代码位置执行,这样内核就为你完成了设备访问,完成之后再从ring0返回ring3。这个过程也称作用户态和内核态的切换。之前有提到过,CPU跟内存他们彼此间是紧密结合的,所以CPU的0级别会映射到内存的某一段处于保护的空间当中。

说这么多也是就是让大家知道,在我们的内存当中,当我们程序运行起来以后,在内存当中它是分成2段的,实际上是3段,最底层这一段叫BIOS的映射程序,即电脑在开机的那一刻,post加电自检以后bios程序就自动映射到这个内存的开端之处了(关于bios加电自检过程后面找一个章节叙述),所以系统能够运行起来,能够完成上电自检的。而自检完成之后,接下来就要载入我们的操作系统,其实是载入操作的内核,因此在在内存中存储BIOS程序的后面一段,是运行内核的一段空间,这段空间就叫内核空间,我们叫kernel space,我要理解的概念。再往后的这段空间,是被多个应用程序彼此之间共享的,因此这段可能运行的是应用程序1,可能是应用程序2等等。

计算机内存按照这样划分是很粗糙的,这样讲解是为了让大家更容易去理解。

事实上这样去进行划分内存是非常容易产生内存碎片的,这里我们要提出一个概念叫碎片的概念,什么是碎片,想象一下如果一个程序刚开始启动的时候他只需要2M内存,系统给了它2M,之后又有程序2加载到内存了,过一会第一个程序又需要2M,因为它运行功能需要加载一些其他数据。这时怎么办,假如内存分配是按需排列的,那就意味着在后面是不是还要重新申请2M,如果这时程序2退出了,那么内存中这些空间就不是连续的了,这两个段是不是就成了碎片了。

所以我们内存管理显然不能是这么一种简单的机制,这个要了解,这其实就意味着,我们操作系统其实是一个非常复杂的东西,它需要管理的任务,需要完成的功能也是非常非常非常复杂的。

接着说我们的应用程序,上一章节我们说过要启动应用程序的方式有两种,一种是让它在后台自动启动,还有一种是我们按需进行启动的。但是我们要按需启动的话,怎么能够指挥计算机去启动某个程序,怎么让我们的操作系统内核能够接收用户的命令呢?这就需要我们给整个操作系统,包括它所提供的各种应用程序提供一个特殊的应用程序,这个特殊的应用程序在广泛意义上称作shell的应用程序,被称作壳,它是整个头型的外壳,是能够实现接收用户指令,理解用户的命令,并且将它传输给内核,由内核指挥着某个进程去启动这么一个界面。所以interface这么一个单词,我们有时候把它翻译成界面,有时候把它翻译成接口,说白了其实指的是同一个意思。我们以后也不加区别的使用界面或者接口,知道是同一个东西就行。

shell本身用来干什么呢?首先要提供一个用户能够跟它进行交互的界面。其次还要将用户的指挥行为翻译成计算机可以理解的命令或者理解翻译成内核可以理解的命令。比如说在我们window系统上,我们在桌面上双击一个图标,点两下鼠标,点两下鼠标以后为什么能够被解析为打开这么个应用程序呢,这时候要内核进行指挥了,但是能够提供一个界面让用户进行双击,并且能够显示一个鼠标的样子,这其实是由shell提供给我们的界面,有shell提供给我们,如果没有shell的话,你怎么跟计算机交互呢?假如你打开你的windows以后,没有桌面,怎么跟它交互,这可能就有点困难了是不是。

所以这就叫shell,shell从广义上来讲它是包含两种类型的,一种叫图形界面的shell,一种叫做命令行的shell,也叫字符界面式shell。这两种第一种叫做GUI 图形用户界面,第二种称叫CLI 命令行界面。无论是GUI还是CLI,它们其实也是应用程序,所以在不同的操作系统上,它们可能有提供有不同的替换的版本

在这里有一个常识大家要知道,目前操作系统类型主要分为window和linux系统,不管是winows系统还是linux系统,它们的都有图形化界面的shell。

linux常见的有3种图形界面,比如说gnome、KDE、XFACE,这3种非常常见的。而在windows上只有一种,而且是无法替换的。有人说可以换,那你换的应该是主题吧,而非是图形界面shell,这个要知道。windows操作系统的shell,尤其是2008之前,它的shell是直接做进内核的,无法替换,没有图形化界面你是没法使用的。而windows server 2008提供了Powershell的接口,也可以不用使用图形界面了。

对于CLI命令行shell来讲,window系统在dos时代,大家知道dos本身就是命令行的,而且是单任务的。linux操作系统,shell程序就多了去了,sh、ksh、psh、zsh、bash等等,有一堆的程序可以使用。

有人可能会有这样一个概念,如果说没有图形界面,我们就靠敲命令来操作系统,操作一个计算机的话,效率是不是非常低啊。事实上你想象中刚好相反,命令行界面的操作速度要远远快于图形界面,前提是能够灵活使用命令才行。事实上我们一个命令有时候可以做出来你需要点几十次鼠标才能完成的工作,而且大家还要建立一个概念,像linux这样的操作系统,本身他是比windows更简单的一种系统。只不过他有一种特性叫做学习曲线,比较陡峭,就入门就比较困难,但学会了以后你会发现,这绝对是一个尤物,是个非常聪明的东西。所以有人把window和linux作了一个对比,说window是一个好看的东西,而linux是一个智慧的东西,而且linus比windows世上要简单的多得多。后面我会讲述操作系统的详细发展史你就会明白了。

更重要的是,linux系统运行比window稳定的多,3年5年不用重启,10年8年不用重启也很常见,而且运行就像刚刚启动的时候一样,依然那么高效。大家可以尝试下能不能用window系统一个星期不重启,window通常是跑不动的,这对一些关键性业务来说是非常重要的,绝对是不可想象的。所以我们windows经常用在两种场景当中,一种是个人桌面,另外一种就是那些比较低端的IDC机房里面可能会用。对一些非常关键性的业务领域大多数都是使用的linux系统。

据TOP500上有统计,全球跑的最快的前五百个计算机90%以上用的都是linux,有一个用windows的恐怕还是还是微软公司自己。我们不扯那么远,回来说我们的GUI和CLI,这是我们的一种特殊应用程序,我们要明白它也是应用程序。而且在这样一个接口下,我们所启动的任何应用程序,如果你一旦关把shell这个应用程序关了,那么在这个接口下所启动应用程序也将会关闭的。

比如说打开windows桌面里,启动了一个word,然后把桌面关了注销了你的word还有吗,肯定没有了。所以这些程序之间还是有关联关系的,我们通过交互式接口启动的程序,跟那个交互接口程序本身有着紧密的关系。这就是我们一个操作系统组成以及我们为什么要用操作系统。但事实上操作系统的功能要比在这里说的要复杂一些的。下面我们简单来说一说内核的功能,能够有个基础的认识,内核主要提供哪些功能呢?

刚才我们在叙述中有说到内核的进程管理协调各个进程、内存管理对系统内存进行管理、还有后续会详细讲到的提供文件系统、提供网络功能、提供硬件驱动、提供安全机制等等这些都是内核的功能。

  • 进程管理
  • 内存管理
  • 文件管理
  • 网络管理
  • 硬件管理
  • 安全管理
  • 系统调用接口(System Call)

不知道大家有没有发现,有哪一个功能是用来帮你完成某一个特定工作的,所以说这是一个通用软件。

不知道大家有没有发现,有哪一个功能是用来帮你完成某一个特定工作的,所以说这是一个通用软件。