文章目录

  • 一、启动:BIOS 与 bootloader
  • 中断的处理过程:
  • 异常的处理过程
  • 系统调用的处理过程


一、启动:BIOS 与 bootloader

    从计算机原理的角度来看,最基本的是以下三部分:

电脑bios文件保存在哪个文件夹里 bios文件位置_系统调用


    其实操作系统一开始并不是放置在内存中的,而是存放在硬盘 disk 上,由 BIOS 【基本输入/输出系统】提供相应的支持,它能在我们按下电源键后,开始检测各种外设,然后加载相应的软件去执行:

电脑bios文件保存在哪个文件夹里 bios文件位置_电脑bios文件保存在哪个文件夹里_02


    如上图所示,BIOS 需要从特定的地址(以 X86 为例,是 Oxf000:fff0,分别表示 CS【段寄存器】和 IP【指令指针寄存器】的值,这两个寄存器合在一起可以形成一个地址的值)开始执行,然后会进行 POST【加电自检】,寻找显卡和执行的 BIOS 。

电脑bios文件保存在哪个文件夹里 bios文件位置_系统调用_03


    bootloader 一般放在硬盘的第一个主引导扇区(一般 512 字节),如上图所示,从 OX7C00,往上 512 个字节,放置的是 bootloader 的代码和数据。它能完成的最主要的功能,就是 把 OS 从硬盘加载到主内存中,这样 OS 就能在内存中执行任务了,控制权就交给 OS 了。


    操作系统与设备和程序交互 ,主要是 interface 的设计的问题:
(1)操作系统面向外设 是 通过 中断 和 IO 。
(2)操作系统面向应用程序是通过系统调用 和 异常。


🖖先来看看三者的粗糙😌概念:
(1)中断(来源于外设)

  • 来自不同的硬件设备的计时器和网络的中断。

(2)异常(来源于不良的应用程序)

  • 非法指令或者其他坏的处理状态。

(3)系统调用(来源自应用程序)

  • 应用程序 主动 向操作系统发出服务请求。

🤙为什么需要中断、异常和系统调用
    为什么应用程序不能直接去访问外设,而是要通过操作系统?因为在计算机运行中,(操作系统)内核是被信任的第三方;只有内核可以执行特权指令;为了方便应用程序,更具有通用性、可移植性。


中断、系统调用、异常的区别:

电脑bios文件保存在哪个文件夹里 bios文件位置_服务例程_04


(异步:操作系统不知道哪时候产生中断。而异常和系统调用,是在特定指令执行后才会产生的,这样的话是同步的。而对于系统调用,发出请求的点是同步的,而返回的点可能是异步的,也可能是同步的。 ❓❓❓没咋懂。)

中断的处理过程:

    产生中断后,需要知道中断是由哪个服务例程进行服务,因此,需要建立一个 ,📃 key是中断号,(比如键盘和鼠标对应的中断号就不同) ,value 是服务例程对应的地址。

  • 硬件:
        在 CPU 初始化时设置中断使能标志,依据内部或外部事件设置中断标志,依据中断向量调用相应中断服务例程。
  • 软件(操作系统):
    (1)编译器保存被打断的执行现场
    (2)根据中断号查询到对应的服务例程的地址,跳转到该地址执行。
    (3)清除中断标记(服务例程)
    (4)编译器恢复之前保存的处理状态
    (应用程序感知不到有中断产生。)
异常的处理过程

    应用程序执行某个特定的指令之后,这个指令触发了异常事件,比如除以零操作,CPU会得到一个异常的 ID 编号,首先需要保存产生异常的执行现场、产生异常的指令、该指令的地址 以及 当前寄存器的内容,然后操作系统会根据异常的编号做相应的处理(可能是退出执行,也可能是弥补服务工作然后恢复,让应用程序重新执行某个指令)。

系统调用的处理过程

    系统调用是操作系统服务的编程接口,通常由高级语言编写(C或者C++),程序访问通常是通过高层次的API接口而不是直接进行系统调用。

  • 三种最常用的应用程序编程接口(API):
    (1)Win32 API 用于 Windows;
    (2)POSIX API 用于 POSIX-based systems (包括UNIX,LINUX,Mac OS X的所有版本);
    (3)Java API 用于JAVA虚拟机(JVM)
  • 电脑bios文件保存在哪个文件夹里 bios文件位置_系统调用_05

  •     如图所示,应用程序 会直接或间接地通过 函数库 访问系统调用接口,然后就会触发 用户态【应用程序在执行的过程中,CPU 处于的一个特权级状态,特权级特别地低,不能够直接访问某些机器指令和直接访问 IO】 内核态 【操作系统运行的过程中,CPU 处于的状态,操作系统可以执行任意一条指令,这时可以完全控制整个计算机系统】 的转换。从而使得控制权从应用程序交给了操作系统,操作系统可以对应用程序发出的参数 ID 做一个标识,然后就可以进行识别,进而完成具体的服务。
  • 系统调用和普通的函数调用的区别:
        当应用程序发出函数调用时,是在一个栈 完成了参数的传递和返回;而系统调用,应用程序、内核 ,是具有各自的堆栈,而且需要完成从用户态到内核态的转换,系统调用的开销更大,不过更安全可靠。
  • 中断、异常、系统调用 的处理过程,以及与应用程序、外设交互的过程,是跨越了操作系统和应用程序、操作系统和外设的边界的,跨越边界的代价:
    (1)在执行时间上的开销超过程序调用的开销。
    (2)开销
    ① 建立中断/异常/系统调用 号 与 对应服务例程 映射关系的初始化开销 (是个表。)
    ② 建立内核堆栈 (操作系统的堆栈不能和应用程序的堆栈混为一谈。)
    ③ 验证参数 (操作系统不信任应用程序,所以为了安全起见。)
    ④ 内核态映射到用户态的地址空间
    ⑤ 内核态独立地址空间