操作系统结构与组成

操作系统结构

操作系统启动

  • 计算机上电
  • 处理器Reset
    • 设置到初始状态
    • 跳转到ROM代码(BIOS)
    • 初始化启动所需最少的设备
  • 从持久存储中加载BootLoader
  • 跳转到BootLoader继续执行
  • 加载OS其余的部分
  • 初始化OS并运行

程序的执行

  • GCC编译、汇编、链接各模块
  • 编译器将程序编译成汇编文件
  • 汇编器将汇编代码编程为可重定位的对象文件
  • 链接器将多个对象文件链接成一个可执行文件

ELF 文件格式

  • ELF(Executable and Linking Format)
    • 可重定位的对象文件(.o)
    • 可执行的对象文件
    • 可被共享的对象文件(.so)
  • 链接视图
    • 由多个section组成
  • 执行视图
    • 由多个segments组成

四个段

  • 代码段:指令序列(text segment)
  • 数据段:全局数据(data segment)
  • 栈(stack)
  • 堆(heap)

布局特点

  • 为了将代码段和数据段分离
  • 栈和堆相向生长
    • 栈自顶向底生长
    • 堆自底向顶生长

全局数据和代码段

  • 编译器静态分配,产生名字和符号索引
  • 链接器翻译索引和重定位地址
  • 加载器最终完成在内存的布局

  • 由编译器布局
  • 进程创建的时候分配、进程结束的时候释放
  • 相对于栈顶(栈指针)寻址

  • 链接器和加载器确定起始地址
  • 通过库函数mallocfree进行分配和释放
  • 应用程序通过库函数进行管理

加载器

Unix下,由加载器Loader完成如下工作

  • 读取一个可执行文件
  • 放置代码、数据、堆和栈
  • 动态链接到共享库
  • 运行应用程序

典型的UNIX操作系统

  • 用户层
    • 应用:程序员编写并编译后的应用程序
    • 库:
      • 精心设计的代码
      • 预编译好的对象
      • 通过头文件定义
      • 通过链接器引入
      • 类似函数调用
      • 程序加载时必须定位
  • 核心层
    • 可移植层:系统调用功能的集合
    • 机器相关层
      • 启动
      • 初始化
      • 中断和例外
      • I/O设备驱动
      • 内存管理
      • 处理器调度
      • 模式切换

程序运行保护

CPU保护

  • 保护CPU不被某个用户程序长期占用
  • 保护用户程序间的尽可能隔离
  • 维护CPU资源的抢占

内存保护

  • 避免用户程序修改OS的代码和数据结构

I/O保护

  • 防止用户程序随意的写入磁盘的任何位置

内核态的保护机制

需要满足处理器支持特权态,可以在特权模式和用户模式下切换。

graph LR
A([用户模式])---->|中断或异常|B([特权模式])
B---->|特殊的返回指令|A
  • 在用户模式下只能执行常规指令和访问用户内存。

  • 在特权模式下可以执行特权指令和访问核心内存。

    • 特权指令包括
      • 读写系统状态寄存器(CSR寄存器)
      • 执行I/O操作
      • 无效快表(TLB)项

中断

硬件中断

  • 由外部事件(外部设备)触发
    • 例如:时钟中断,硬盘读写请求完成,移动鼠标,键盘输入
  • 硬件中断产生与当前正在执行的进程无关
  • 硬件中断可以被关闭(CSR寄存器)

可编程中断(软件中断)

  • 由编程者用相应指令触发(syscall)

中断处理程序

触发中断后,系统内核跳转到中断处理程序中,处理完毕后恢复被中断的进程。

异常

  • 由当前正在执行的进程产生
  • 类型:
    • 出错:处理后,重新执行触发异常的指令
    • 陷入:处理后,执行触发异常指令的下一条指令
    • 中止:不再执行指令

系统调用机制

关键和核心功能由内核完成,用户仅仅进行调用,而不修改内核代码

过程

  • 系统调用参数传递
    • 寄存器传参
      • 可用寄存器个数
      • 系统调用参数个数
    • 内存向量(数组)传参
      • 一个寄存器传递起始地址
      • 向量位于用户地址空间
    • 堆栈传参
      • 类似内存向量
      • 遵循过程调用的约定
  • 系统模式从用户态切换到内核态
  • 执行系统调用功能
  • 返回结果,切换到用户态
    • 通过寄存器返回结果
    • 将错误返回给调用者

系统调用 对比 库函数调用

  • 系统调用
  • 陷入内核,在内核态执行具体功能
  • 依赖于操作系统
  • 内核态和用户态切换
  • 库函数调用
    • 在进程用户态空间执行和执行功能
    • 标准C库函数相同
    • 过程调用
内存管理
  • 内核
    • 分配带硬件保护的页面
    • 分配一大块(多个页面)给库
    • 不关心小粒度的分配
    • 通过sbrk/brk/mmap等函数分配页面,改变数据段长度
    • 提供malloc/free等函数用于分配和释放内存
    • 应用通过这些函数细粒度管理内存
    • 当页面用完后,库函数会向内核批量请求更多的页面

内核结构

宏内核(Linux,Windows,BSD Unix)

  • 在内核态实现操作系统所有功能
  • 应用通过调用系统调用(syscall)使用操作系统提供的功能
  • 好处
    • 内核所有函数共享地址空间
    • 内核模块通信性能高
  • 缺点
    • 不稳定:模块的崩溃会造成系统的崩溃
    • 不灵活:新增模块需要对内核进行编程

微内核(Mach,MINIX)

  • 操作系统功能服务作为用户态的常规进程
  • 应用通过消息获取服务进程的服务
  • 好处
    • 开发灵活
    • 故障隔离
  • 缺点
    • 进程间的通信效率低
    • 保护机制不完整

库操作系统(Exokernel,ExOS)

  • 应用程序直接通过库与底层硬件交互
  • 好处
    • 效率高
  • 缺点
    • 通用性差

操作系统组成

  • 处理器管理
  • 内存管理
  • I/O设备管理
  • 文件系统
  • GUI