基本概念

  • CPU 控制流:CPU 所执行的地址序列
  • 正常控制流:按指令存放顺序或转移类指令指示地址得到的控制流
  • ECF: Excptional Control of Flow
  • process descriptor: 结构类型 task_structure
  • task_list: 双向循环列表,每个元素为进程描述符
  • TSS: Task State Segment
  • 逻辑控制流:进程确定的指令执行地址序列
  • 物理控制流:多个逻辑控制流组成
  • concurrency: 并发,不同进程的逻辑控制流在时间上交错
  • parallelism: 并行,并发的特例,同时进行的两个进程
  • time slice: 连续执行同一个进程的时间段
  • 时间片轮转处理器调度

context switching

实现班班通进程中指令交替执行的机制

  • 进程的上下文:物理实体和支持进程运行的环境
  • 用户堆栈:运行时堆和用户栈
  • 用户级上下文:程序块、数据块、用户堆栈等组成的用户空间信息
  • 系统级上下文:进程标识信息、进程现场信息、进程控制信息(各种内核数据结构)和系统内核栈组成的内核空间信息
  • 硬件/寄存器上下文
  • 上下文切换
    • 将寄存器上下文保存到当前进程的系统级上下文中
    • 将新进程系统级上下文中的现场信息恢复到寄存器中
    • 将控制转移到新进程

memory mapping

将进程虚拟地址空间中的一个区域与硬盘上一个对象关联,初始化一个 vm_area_struct 结构
mmap 函数

  • void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset
  • 返回值 MAP_FAILED(-1), 成功则为指向映射区域的指针
  • prot 访问权限 PROT_EXE/READ/WRITE/NONE
  • flags 对象类型
    • 普通文件
      • MAP_PRIVATE: 只读代码和已初始化数据,私有对象,写时拷贝
        • 私有的写时拷贝页
      • MAP_SHARED: 共享对象
    • 匿名文件:MAP_ANON 内核创建,全部由 0 组成。对应区域页面称为 demand-zero page

loader

  • execve() 启动加载器
  • int execve(char *filename, char *argv[], *envp[])
  • 失败 -1
  • 成功 _start(定义于 crtl.o)->__libc_init_first, _init -> atexit() 登记终止处理函数 -> exit(main()) -> _exit()
  • 加载执行 fork() -> execve()

Exception and Interrupt

异常

fault

  • page fault
  • div by 0
  • segmentation fault

trap

  • 陷阱指令, programmed exception
  • 系统调用
  • 断点设置:int 3, CCH
  • into(溢出检查), INT n(软中断), bound(地址越界检查)

abort

中断

  • 中断请求信号线
  • maskable interrupt & nonmaskable interrupt, NMI

处理过程

保护断点和程序状态 -> 关中断(中断允许位置 0) -> 识别事件(irq_handle) -> 转到相应处理程序执行(操作系统)

  • PSWR:程序状态字寄存器,保存 PSW (IA-32 中为 EFLAGS)。 也需保存
  • 软件识别(程序)/硬件识别(向量中断方式)
  • 中断向量表:保存中断向量,每个中断和异常有一个中断类型号

IA-32+Linux

  • 中断向量(256 种),前 32 个保留给处理器
  • 向量号(中断类型号)
  • INT n: CPU 跳转到中断服务程序
  • 实地址模式(Real Mode),8086 兼容模式,20 位储存器寻址空间(1MB), 中断向量表为 00000 - 003FF, 256*4=1KB
  • 19 个确定类型。Linux 128 为系统调用, Windows 46 为系统调用
  • 保护模式,使用中断描述附表(IDT, Interrupt Descriptor Table), 256*8=2KB
  • 中断门(中断),陷阱门(异常)
    • 31-16: 偏移地址
    • P(段存在), DPL(最低特权等级), 0, 段选择符(中断门 1110,陷阱门 1111,任务门 0101),00000000
    • 段选择符:GDT 和 LDT 中的位置
    • 15-0:偏移地址,异常或中断服务程序第一条指令所在偏移量
  • 任务门:只包含 TSS 选择段,指向 GDT 中的一个 TSS 段描述符
    • 双重故障#DF 通过任务门实现的唯一异常

IA-32 处理异常和中断

  • 确定类型号 i,从 IDTR 指向的 IDT 中取出第 i 个表项 IDTi
  • 根据 IDTi 中的段选择符,从 GDTR 指向的 GDT 中取得相应的段描述符,得到服务程序所在段 DPL、基地址(Linux 中为 0)
  • 比较 CPL 与 DPL
  • 检查特权级变化。从用户栈转换到内核栈:
    • 读 TR 寄存器,访问 TSS 段
    • 将 TSS 段中的内核栈段选择符和栈指针写入 SS 和 ESP,在内核中保存原来的用户栈 SS 和 ESP
  • 若发生的是故障,将逻辑地址写入 CS 和 EIP
  • 栈中保存 EFLAGS,CS,EIP。若是中断门,IF 清 0
  • 若产生硬件出错码,保存在内核栈中
  • 将 IDTi 中的段选择符载入 CS,偏移地址装入 EIP
  • 处理异常和中断,结束后由 IRET 返回
    • 从内核栈中弹出 EIP,CS,EFLAGS
    • 检测特权级别
    • 从内核栈中弹出 SS,ESP
    • 检查 DS,ES,FS,GS

Linux 处理异常和中断

  • IDT 初始化:完成 GDT,GDTR,IDT,IDTR 设置
    • interrupt gate: DPL=0, TYPE=1110
    • system interrupt gate: DPL=3, TYPE=1110, int3
    • system gate: DPL=3, TYPE=1111, into,bound,int $0x80
    • trap gate: DPL=0, TYPE=1111, INT n(n!=3,128)
    • task gate: DPL=0, TYPE=0101
  • 异常处理
    • 准备阶段:内核栈中保存现场信息
    • 处理阶段:若发送信号给当前进程,若有对于的信号处理程序,则执行,否则调用 abort 例程终止进程
    • 恢复阶段
  • 信号处理
    • 定义信号处理函数替换默认信号处理函数,并通过 signal 函数将自定义信号处理函数注册到系统中
    • typedef void (*sighandler_t)(int);
    • sighandler_t signal (int signum, sighandler_t handler);
    • nonlocal jump:
      • sigsetjmp: 第一次调用返回 0,而后返回非 0
      • siglongjmp: sigsetjmp 一次后,返回到 sigsetjmp 函数
  • 中断处理
    • I/O 中断
      • IRQ 线连接到 PIC(programmable interrupt controller)
      • IRQ 引脚:PIC 上,都有编号
    • 时钟中断
    • 处理器中断
    • 中断服务程序
      • 准备阶段
      • 处理阶段:ISR(Interrupt Server Routine)
      • 恢复阶段
  • 系统调用
    • 系统级函数:系统调用及其对应的封装函数
    • 系统调用处理程序:system_call