• 学习Traps, interrupts, and drivers

1.保护性控制转移
  异常和中断都是保护性控制转移,让处理器从用户模式切换到内核模式(CPL=0),这样用户代码不会对内核或者其他环境造成影响。中断是由外部异步事件导致的处理器保护性控制转移,比如外设I/O的通知信号。异常是正在运行的代码同步事件导致的控制转移,比如除零或者访问无效内存。

  为了确保控制转移真的被保护,x86平台上有两种机制:

  • 中断描述符表。处理器确保中断和异常引起内核进入特定的入口点。

    • x86允许最多256个不同的中断和异常入口点,每个都有一个独特的中断向量。向量是0到255的数字,中断向量由中断源决定:不同设备,错误条件以及请求内核产生中断的不同向量。CPU使用向量作为索引访问处理器中断描述符表(IDT),这个是内核在内核私有内存设置的。处理器从合适的入口处加载:

      • 加载到EIP寄存器的值,这是个指向处理这种类型异常的内核代码的指针
      • 加载到CS寄存器的值,包含特权级0-1
  • 任务状态段。处理器需要存放中断异常发生之前的旧的处理器状态,比如原始EIP值和CS值,这样可以之后还原到之前的状态。保存这个的位置必须要受保护不能随意修改。

  因此,x86处理器处理中断时会导致特权级由用户转为内核,也会将堆栈切换到内核内存中。任务状态段具体指明段选择子和堆栈的地址。处理器将SS, ESP, EFLAGS, CS, EIP和可选错误码压入堆栈中,之后从中断描述符中加载CS和EIP,设置ESP和SS指向新的堆栈

1.1.Interrupts

  • External (hardware generated) interrupts.

    • External interrupts are received through pins on the processor.
  • Software-generated interrupts.
    • The INT n instruction permits interrupts to be generated from within software by supplying an interrupt vector number as an operand.

1.2.Exceptions

  • Processor-detected program-error exceptions.
  • Software-generated exceptions.
  • Machine-check exceptions

1.2.1.Program-Error Exceptions
  The processor generates one or more exceptions when it detects program errors during the execution in an application program or the operating system or executive. Intel 64 and IA-32 architectures define a vector number for
each processor-detectable exception. Exceptions are classified as faults, traps, and aborts.

  • Faults — A fault is an exception that can generally be corrected and that, once corrected, allows the program to be restarted with no loss of continuity. When a fault is reported, the processor restores the machine state to the state prior to the beginning of execution of the faulting instruction. The return address (saved contents of the CS and EIP registers) for the fault handler points to the faulting instruction, rather than to the instruction following the faulting instruction.
  • Traps — A trap is an exception that is reported immediately following the execution of the trapping instruction.Traps allow execution of a program or task to be continued without loss of program continuity. The return address for the trap handler points to the instruction to be executed after the trapping instruction.
  • Aborts — An abort is an exception that does not always report the precise location of the instruction causing the exception and does not allow a restart of the program or task that caused the exception. Aborts are used to report severe errors, such as hardware errors and inconsistent or illegal values in system tables.

1.2.2.Software-Generated Exceptions
  The INTO, INT1, INT3, and BOUND instructions permit exceptions to be generated in software. These instructions allow checks for exception conditions to be performed at points in the instruction stream. For example, INT3 causes a breakpoint exception to be generated.

1.2.3.Machine-Check Exceptions
  The P6 family and Pentium processors provide both internal and external machine-check mechanisms for checking the operation of the internal chip hardware and bus transactions.

2.xv6 trap/interrupts

  trap(实现系统调用)和中断主要区别:

  • trap是由当前进程触发的,中断是由设备产生的,可能和当前进程没有关系。
  • 中断门和trap门只有一位不相同,具体是中断门清除 EFLAGS 寄存器的 IF 位。所以运行trap处理程序时,还是会响应其它中断。

2.1.system call

  When a process needs to invoke a kernel service, it invokes a procedure call in the operating system interface. Such a procedure is called a system call. The system call enters the kernel; the kernel performs the service and returns. Thus a process alternates between executing in user space and kernel space.
  The kernel uses the CPU’s hardware protection mechanisms to ensure that each process executing in user space can access only its own memory. The kernel executes with the hardware privileges required to implement these protections; user programs execute without those privileges. When a user program invokes a system call, the hardware raises the privilege level and starts executing a pre-arranged function in the kernel.

  Each process’s address space maps the kernel’s instructions and data as well as the user program’s memory. When a process invokes a system call, the system call executes in the kernel mappings of the process’s address space. This arrangement exists so that the kernel’s system call code can directly refer to user memory. In order to leave room for user memory to grow, xv6’s address spaces map the kernel at high addresses, starting at 0x80100000.
系统调用流程图:
2.2.Interrupts

回答以上问题:
Q1: how to find interrupt handler?
1.Hardware maps interrupt type to interrupt number in the traps.h(xv6).
x86 Interrupt numbers:

  1 // x86 trap and interrupt constants.2 // Processor-defined:                                                                                                       4 #define T_DIVIDE         0      // divide error5 #define T_DEBUG          1      // debug exception6 #define T_NMI            2      // non-maskable interrupt7 #define T_BRKPT          3      // breakpoint8 #define T_OFLOW          4      // overflow9 #define T_BOUND          5      // bounds check10 #define T_ILLOP          6      // illegal opcode11 #define T_DEVICE         7      // device not available12 #define T_DBLFLT         8      // double fault13 // #define T_COPROC      9      // reserved (not used since 486)14 #define T_TSS           10      // invalid task switch segment15 #define T_SEGNP         11      // segment not present16 #define T_STACK         12      // stack exception17 #define T_GPFLT         13      // general protection fault18 #define T_PGFLT         14      // page fault19 // #define T_RES        15      // reserved20 #define T_FPERR         16      // floating point error21 #define T_ALIGN         17      // aligment check22 #define T_MCHK          18      // machine check23 #define T_SIMDERR       19      // SIMD floating point error24 25 // These are arbitrarily chosen, but with care not to overlap26 // processor defined exceptions or interrupt vectors.27 #define T_SYSCALL       64      // system call28 #define T_DEFAULT      500      // catchall29 30 #define T_IRQ0          32      // IRQ 0 corresponds to int T_IRQ31 32 #define IRQ_TIMER        033 #define IRQ_KBD          134 #define IRQ_COM1         435 #define IRQ_IDE         1436 #define IRQ_ERROR       1937 #define IRQ_SPURIOUS    31

2.OS sets up Interrupt Descriptor Table ( also called interrupt vector) at boot.

  • IDT is in memory
  • Each entry is an interrupt handler
  • OS lets hardware know IDT base
  • Defines all kernel entry points
  • Hardware finds interrupt handler using interrupt number as index into IDT
    • handler = IDT[intr_number]

流程图:

2.1.Setting Up the IDT
  Set up the IDT to handle interrupt vectors 0-31 (the processor exceptions). The header files inc/trap.h and kern/trap.h contain important definitions related to interrupts and exceptions that you will need to become familiar with. The file kern/trap.h contains definitions that are strictly private to the kernel, while inc/trap.h contains definitions that may also be useful to user-level programs and libraries.

2.2.The overall flow of control

      IDT                   trapentry.S         trap.c+----------------+
|   &handler1    |---------> handler1:          trap (struct Trapframe *tf)
|                |             // do stuff      {
|                |             call trap          // handle the exception/interrupt
|                |             // ...           }
+----------------+
|   &handler2    |--------> handler2:
|                |            // do stuff
|                |            call trap
|                |            // ...
+----------------+...
+----------------+
|   &handlerX    |--------> handlerX:
|                |             // do stuff
|                |             call trap
|                |             // ...
+----------------+

2.3.代码实现
  每个异常或中断都应该在 trapentry.S 有自己的处理函数handler,trap_init() 用来初始化IDT。每个异常处理是一个保存在堆栈上的 struct Trapframe ,调用 trap() 指向这个 Trapframe。trap() 之后处理异常中断。
  在kern/trapentry.S 中定义有两个宏TRAPHANDLER/TRAPHANDLER_NOEC,如下所示:

#define TRAPHANDLER(name, num)                      \.globl name;        /* define global symbol for 'name' */   \.type name, @function;  /* symbol type is function */       \.align 2;       /* align function definition */     \name:           /* function starts here */      \   pushl $(num);                           \jmp _alltraps#define TRAPHANDLER_NOEC(name, num)                 \.globl name;                            \.type name, @function;                      \.align 2;                           \name:                               \pushl $0;                           \pushl $(num);                           \jmp _alltraps

  这两个宏的作用:
  利用TRAPHANDLER和TRAPHANDLER_NOEC宏来实现interrupt handler。这两个宏所生成的代码的作用是,根据传入参数定义handler的“标签”,然后进行一些压栈操作。如果系统没有压入错误码,就压入一个0;然后压入中断号,接下来跳转到一个名为_alltrap的函数。

  每个handler都要在栈上构造一个结构体 struct trapframe (见inc/trap.h),并调用 trap.c 中的 trap()。

 78 _alltraps:79     pushl %ds80     pushl %es81     pushal82     movw $GD_KD,%ax83     movw %ax,%ds84     movw %ax,%es85     pushl %esp86     call trap
  • 值压入堆栈构造一个stuct Trapframe
  • 加载 GD_KD 到 %ds 和 %es
  • pushl %esp 将指向 Trapframe 的指针作为 trap() 的参数
  • 调用 trap function

  当中断发生后,CPU会自动切换到一个新的栈,然后自动地将当前运行程序的EFLAGS寄存器压入栈中,然后压入CS和IP,然后对于一些特殊的异常CPU还会压入error code,然后才会跳转到中断服务程序的第一条指令 – 这第一条指令就是在handler中。
  然后,handler就开始压栈了。为了保证Trapframe结构的一致性和完整性,对于CPU没有压入error code的情况,TRAPHANDLER_NOEC定义的handler首先压入一个0用于占位。 接着,TRAPHANDLER和TRAPHANDLER_NOEC都压入了trap number。
  最后,两者都跳转到_alltraps,这是每个handler都一样的代码,它的作用依然是继续补充Trapframe结构,注意压栈顺序要和Trapframe结构中的顺序一致。经过上述一系列操作之后,一个完整的Trapframe结构诞生了,也就意味着保存现场的工作完成。

  gdb 调试_alltraps:
  设置断点:

+ symbol-file obj/kern/kernel
(gdb) b *0x7c00
Breakpoint 1 at 0x7c00
(gdb) c
(gdb) b *0x100025
Breakpoint 2 at 0x100025
(gdb) b *0xf0105fbb          //查看obj/kern/kernel.asm: _alltraps
Breakpoint 3 at 0xf0105f4e: file kern/trapentry.S, line 57.


如上所示,入栈之前ds=es=0x23,此时栈地址为0xefffffe0和0xefffffdc,执行push %ds 和push %es之前和之后,地址数据:

 //push %ds
(gdb) x/x 0xefffffe0
0xefffffe0:     0xf01d3000
(gdb) si
=> 0xf0105fbc <_alltraps+1>:    push   %es
_alltraps () at kern/trapentry.S:84
(gdb) x/x 0xefffffe0
0xefffffe0:     0x00000023//push %es
(gdb) x/x 0xefffffdc
0xefffffdc:     0xf01000e5
(gdb) si
=> 0xf0105fbd <_alltraps+2>:    pusha
_alltraps () at kern/trapentry.S:85
(gdb) x/x 0xefffffdc
0xefffffdc:     0x00000023

trap_init() 使用这些handler的地址来初始化IDT。

74     SETGATE(idt[T_DIVIDE], true, GD_KT,t_divide, 0);
75     SETGATE(idt[T_DEBUG], true, GD_KT,t_debug, 0);
76     SETGATE(idt[T_NMI], false, GD_KT,t_nmi, 0);
77     SETGATE(idt[T_BRKPT], true, GD_KT,t_brkpt, 3);
78     SETGATE(idt[T_OFLOW], true, GD_KT,t_oflow, 0);...

Q2:why switch stack?

参考资料:
Documents/work/code/jos/lab3
https://linbo.github.io/2017/10/22/xv6-syscall_1

xv6 Traps, interrupts, and drivers相关推荐

  1. 资源向导之 JOS 计划 MIT 6.828

    Project of JOS update: 2016.03.18 哇,JOS过去一段时间了,有一些同学可能获得JOS实验初始的源代码比较困难,原因可能是GFW也可能是JOS官方他们每学期都可能会课程 ...

  2. MIT 6.S081 Lab4 traps

    #Lab4: traps #Source #My Code #Motivation #Backtrace (moderate) #Motivation #Solution #S0 - RISC-V 栈 ...

  3. XV6源代码阅读-中断与系统调用

    XV6源代码阅读-中断与系统调用 Exercise1 源代码阅读 1.启动部分: bootasm.S bootmain.c 和xv6初始化模块:main.c bootasm.S 由16位和32位汇编混 ...

  4. xv6操作系统源码阅读之init进程

    首先看main函数,里面调用了一个userinit函数,这就是启动第一个init进程. // Bootstrap processor starts running C code here. // Al ...

  5. xv6源码阅读——中断与异常

    目录 说明 陷入机制概述 Traps from user space 调用逻辑 ecall uservec usertrap usertrapret userret sret Traps from k ...

  6. Xv6操作系统导论(第三章)

    第三章 页表 页表是操作系统为每个进程提供私有地址空间和内存的机制.页表决定了内存地址的含义,以及物理内存的哪些部分可以访问.它们允许xv6隔离不同进程的地址空间,并将它们复用到单个物理内存上.页表还 ...

  7. Xv6 Operating System Organization

    Operating System Organization 参考 xv6-riscv-book Chapter 2 Operating system organization 文章目录 Operati ...

  8. XV6实验(2020)

    XV6实验记录(2020) 环境搭建 参考连接 Lab guidance (mit.edu) 6.S081 / Fall 2020 (mit.edu) xv6 book中文版 Lab1:Xv6 and ...

  9. xv6源码分析—第一个用户进程

    关于进程 进程是一个抽象概念,它让一个程序可以假设它独占一台机器.进程向程序提供"看上去"私有的,其他进程无法读写的内存空间,以及"看上去"仅执行该程序的CPU ...

  10. 6.S081——陷阱部分(一文读懂xv6系统调用)——xv6源码完全解析系列(5)

    0.briefly speaking 这篇博客将要开始尝试阅读和研究与Xv6陷阱机制相关的代码,主要有以下文件,最重要的是结合Xv6 book将Xv6处理陷阱的相关逻辑和流程弄透.在Xv6的语境中所谓 ...

最新文章

  1. HttpSessionActivationListener接口 学习笔记
  2. 谷歌量子计算登上Nature封面,首次实现量子优越性,里程碑式突破
  3. 经典技术文章翻译(1):COM+集成:.NET Enterprise Services 如何帮你建立分布式应用(2)
  4. 2011年c语言二级计算机考试,2011年9月全国计算机等级考试二级C语言机试
  5. 周期长度和(KMP)
  6. CSS之Responsive设计的关键三步
  7. php 模数 指数 公钥生成_php实现JWT认证
  8. GenseeSDK 使用Kotlin要注意TODOAndroid Studio关闭TODO
  9. 小米路由器 梅林_WIFI6真的有用吗?小米ALOT路由器AX3600上手体验!小米智能家居生态之选及选购分析...
  10. 【cl】本地安装maven的jar包报错Artifact is already in the local repository
  11. 汇编语言32位加减乘除运算题
  12. SpringBoot 2.0 整合Mybatis详细步骤
  13. 自助友情链接php源码,基于ThinkPHP内核开发的友情链接交易系统平台源码_支持在线支付宝及时到账支付...
  14. 笔记 -凸函数 /KL距离
  15. Win10巧用自带输入法轻松打出特殊字符
  16. 小强统一认证中心-部署实例
  17. 城市记忆(3)灵州----灵武
  18. 计算机论文中期考核报告,计算机与人工智能学院硕士研究生中期考核办法
  19. 有哪些好用的视频录制工具?
  20. 同城信息发布小程序开发制作

热门文章

  1. android切换输入法工具类
  2. bigworld引擎
  3. attachEvent兼容各浏览器事件
  4. jade选峰之后怎么去掉_jade使用教程
  5. 基于proteus的CPU控制器设计(微程序版)
  6. Android Activity防劫持方案
  7. lgg7刷机包下载_LG G7 恢复Download回官方。
  8. 什么原数据更容易平稳_判定数据序列平稳与否的方法都有哪些,什么是平稳序列...
  9. 产品经理应该看什么书?
  10. win10保护色设置及还原