0%

传统IO

传统IO过程
  1. CPU发起IO请求,每次只能请求一个字
  2. 磁盘数据写入缓冲区后,通过IO中断通知CPU
  3. CPU将缓冲区数据通过寄存器写入内核缓冲区(内存中)
  4. CPU将内核缓冲区(内存中)的数据拷贝到用户缓冲区(内存中)
缺点
  1. CPU效率低下:CPU需要频繁得处理IO请求
  2. 传输效率低下:数据先从磁盘缓冲区拷贝到寄存器后才到拷贝到内存
image.png

引入DMA后的IO

将数据搬运的工作全部交给DMA控制器,CPU不需要参与

引入DMA后的IO过程
  1. CPU发送IO请求到DMA
  2. DMA拷贝磁盘数据到内核缓冲区
  3. DMA拷贝完后向CPU发送IO中断请求
  4. CPU将内核缓冲区的数据拷贝到用户缓冲区
Read more »

第七章 中断

中断与异常

image.png

中断执行过程

image.png

当通过键盘给当前进程输入参数时的流程(IO中断)

中断流程

  1. 用户键盘输入
  2. 键盘控制器生成扫描码并触发中断 (IRQ1)
  3. CPU 暂停当前进程,响应中断
  4. CPU执行中断处理程序,获取键盘输入
  5. 恢复被中断的任务
  6. 用户进程读取缓冲区输入(系统调用,使用“陷阱”内中断)

用户如何使用系统其他资源(系统调用)

用户态的程序只能使用内存中用户段,不能使用内核段。内核态可以访问任何内存数据。

Read more »

第六章 操作系统安全

缓冲区溢出攻击

原理

缓冲区溢出通常发生在程序使用固定大小的内存缓冲区来存储用户输入时,没有对输入数据的长度进行适当检查。攻击者利用这一点,将过大的输入数据注入缓冲区,导致:

  • 覆盖关键数据:覆盖函数的返回地址、指针或其他重要变量。

  • 注入恶意代码:将攻击代码注入溢出的内存区域,并操纵程序跳转到攻击代码执行。

  • 控制程序执行流:通过覆盖返回地址或函数指针,改变程序的正常执行逻辑。

解决办法

  • 栈随机化

  • 栈破坏检测

  • 限制可执行代码区域

image.png

操作系统安全算法

1. 用户身份验证:散列算法

Read more »

第五章 指令系统结构

指令

执行流程

  1. 取指阶段:以PC作为第一个字节的地址,从内存中读出10个字节
  2. 译码阶段:指令字段译码,将操作数的值写到ALU读取的寄存器位置
  3. 执行阶段:ALU根据操作数和操作码计算值
  4. 访存阶段:读写内存位置
  5. 写回阶段:将结果值写入寄存器
  6. 更新PC:更新PC指向下一条指令的地址
image.png

指令示例

irmovq

将一个 64 位的立即数(常数)加载到目标寄存器中

image.png

pushq

Read more »

文件系统操作

整体架构

在文件系统和应用程序间有一层抽象层,称为虚拟文件系统(VFS)

  • VFS作为抽象层向应用层提供了统一的文件接口(read,write等)
  • VFS实现了一些公共的功能,如Directory Cache和Page Cache等
  • 规范了接口

VFS向应用层提供统一接口,具体实现不同文件系统有不同实现,VFS将函数指针指向对应函数

核心操作

文件系统的注册

在Linux中,具体文件系统通常是一个内核模块,在内核模块被加载时完成文件系统的注册

磁盘挂载

Read more »

磁盘的工作原理

磁盘读写的过程
  1. 磁盘移动,找到要读的柱面(cylinder,简称C)
  2. 从柱面选择具体读哪个磁道(magnetic head,简称H),选择对应的磁头上电(每次只能有一个磁头上电)
  3. 旋转磁盘,将对应磁道中要读写的那个扇区(sector,简称S)转到磁头下方
  4. 开始读写,将扇区中的内容读到内存缓存区中,或者将内存缓存区中的内容写到该扇区中

生磁盘的使用

第一层抽象:从扇区到磁盘块请求(抽象读写请求)

正常寻址需要通过CHS三维向量,但是可以通过一位扇区编号编址

磁盘读写时间 = 寻道时间(选择柱面)+旋转时间(选择+读取扇区)+传输时间(磁生电活电生磁)

其中寻道时间占主导,故每次只读/写一个扇区是对于时间的浪费,故一次读/写多个扇区,称为

第二层抽象:多个进程产生的磁盘请求队列(抽象读写方法)
Read more »

第三章 内存管理

程序重定位

在编译形成可执行程序时,用到的地址都是从0开始的相对地址,也被称为逻辑地址。但被加载到内存后可能使用任意一块空闲地址,所以需要将逻辑地址转化成内存中实际的物理地址,即重定位

有以下几种解决方法:

  1. 编译时重定位:需要在编译时确定哪块内存空间空闲,且在装入前不允许使用(用于执行固定任务的计算机系统,如嵌入式系统)

  2. 载入时重定位:在程序载入时,根据初始内存地址修改程序里的逻辑地址,但如果进程阻塞换出内存后换入时的地址不一定是之前的地址,造成错误

  3. 运行时重定位(PC机使用):在指令执行时才将逻辑地址转化为物理地址,取出指令—修改地址(存储管理部件MMU计算)—执行指令

    基地址存在PCB中,在内存基地址修改时更新,在执行时加载到寄存器中使MMU修改地址

分段

程序由若干段组成,每段都有各自的用途

  • 代码段:程序指令形成的段,只读
  • 数据段:存放程序使用的数据,可读可写
  • 栈:实现函数调用,通常只能向下(低地址)增长
  • 函数库:include的函数库,可有可无

由于各个段有不同的语义及限制操作,所以需要进行区分。

Read more »

CPU调度策略

任务调度策略的三个基本准则

  • 任务周转时间:从新建到完成的时间
  • 任务响应时间:从提交请求到首次响应的时间(前台任务关心)
  • 系统吞吐量:一段时间内系统能完成的任务数

调度算法

  1. 先来先服务

  2. 最短作业优先调度:不可抢占,平均周转时间短(作业运行时间只能近似给出)

  3. 最短剩余时间有限:最短作业优先的可抢占版本

  4. 时间片轮转调度:保证响应时间

    时间片设得太短会导致过多的进程切换,降低了CPU效率设得太长会引起对短作业的交互请求的响应时间变长

  1. 多级反馈队列调度:动态调整任务类型(近期多IO可能为前台任务,无IO时间片结束未完成可能为后台大任务)

    运行流程

    1. 设置多级就绪队列,各级队列优先级从高到低,时间片从小到大
    2. 新进程到达时先进入第1级队列,按FCFS原则排队等待被分配时间片。 若用完时间片进程还未结束,则进程进入下一级队列队尾。如果此时已经是在最下级的队列,则重新放回最下级队列队尾
    3. 只有第k级队列为空时,才会为k+1级队头的进程分配时间片

调度算法比较

Read more »

进程

运行中的程序(区别于未运行的静态程序),需要有数据结构保存当前运行的信息(PCB),便于切换不同进程

进程的状态

process_state

进程的切换

操作系统切换进程(宏观)

例子为进程运行到磁盘读写操作后与其他进程的切换

process

操作系统切换进程的PCB(微观)

PCB_use
Read more »

第一章 绪论

计算机体系结构

image.png

计算机启动后发生了什么

image.png
  1. 上电自检

    主板的固件(BIOS 或 UEFI)执行硬件检测,检查 CPU、内存、显卡、键盘等设备是否正常

  2. 加载 BIOS 或 UEFI

    1. CPU 开始执行 0xFFFFFFF0 地址处的指令,该地址处是一条 JUMP 指令,这条指令清空了基址寄存器的值,并让指令跳回到 BIOS 开始处(物理地址为 0xF0000,参考上图 0xF0000 处的标识)以执行 BIOS

    2. BIOS 或 UEFI 固件初始化计算机硬件,完成底层配置。

    3. 确认引导顺序(启动顺序),如硬盘、USB 设备或网络启动。

    4. 加载引导程序(Bootloader)的第一部分,通常位于启动设备的引导扇区。

  3. 主引导记录(Master Boot Record, MBR)

    BIOS 从指定的启动设备中读取主引导记录

  4. 启动加载器(Bootloader)

    启动加载器是一个小型程序,负责加载操作系统内核(常用:GRUB多操作系统支持,配置灵活;Windows Boot Manager用于加载 Windows 操作系统)

  5. 内核初始化

    操作系统内核接管硬件的控制。执行真正的根文件系统中的 /sbin/init 进程,即系统的 1 号进程。此后,系统的控制权就全权交给 /sbin/init 进程了

  6. 系统初始化

    /sbin/init 进程是系统其它所有进程的父进程,当它接管了系统控制权后,它会根据 /etc/inittab 文件来执行相应的脚本,从而完成一系列的系统初始化操作

  7. 用户登陆

程序是如何运行的

准备阶段:

  1. 通过shell获取可执行程序地址,参数和环境变量
  2. 通过fork创建子进程
  3. 通过execve替换当前进程的地址空间,使用加载器将程序加载到内存中
  4. shell调用wait 或 waitpid 系统调用等待子进程执行结束

运行阶段:

Read more »