MIT6.828_Lecture 8: Interrupts, System calls, and Exceptions in xv6

原文点这里
1.硬件现在需要关注(attention)! 软件必须搁置当前的工作并做出响应

2.为什么hw现在需要关注?
MMU无法翻译地址
用户程序除0
用户程序想要执行内核代码(INT)
网络硬件(Network hardware)想要传递一个数据包(deliver a packet)
计时器硬件希望提供一个“tick”
内核cpu到cpu的通信,例如刷新(flush)TLB (IPI)

3.这些 “traps” 大致分为三类:
Exceptions (page fault, divide by zero)
System calls (INT, intended exception)
Interrupts (devices want attention)

4.设备中断从何而来?
diagram:
    CPUs, LAPICs, IOAPIC, devices
    data bus
    interrupt bus
中断告诉内核设备:硬件需要注意(attention)
驱动程序(the driver)(在内核中)知道如何告诉设备去做事情
中断处理程序通常调用相关的驱动程序
但其他安排是可能的 (schedule a thread; poll)

5.trap()如何知道哪个设备被中断了?
即tf->trapno == T_IRQ0 + IRQ_TIMER从哪里来?
内核告诉LAPIC/IOAPIC使用哪个向量号,例如timer是向量32
    page faults &c也有向量(正如我们在上节课中看到的)
    LAPIC / IOAPIC是PC硬件的标准部件
    每个CPU有一个LAPIC
IDT将指令地址与每个向量相关联
    IDT格式由Intel定义,内核配置
每个向量都跳转到 alltraps
CPU通过IDT发送多种陷阱
    low 32 IDT entries具有特殊的固定含义
xv6设置系统调用(IRQ)来使用IDT条目64 (0x40)
要点:vector number揭示了中断的来源

6.diagram:
IRQ or trap, IDT table, vectors, alltraps
IDT:
    0: divide by zero
    13: general protection
    14: page fault
    32-255: device IRQs
    32: timer
    33: keyboard
    46: IDE
    64: INT

7.让我们看看xv6如何设置中断向量机制
lapic.c / lapicinit()——告诉LAPIC硬件使用vector 32作为定时器
trap.c / tvinit()——初始化IDT,因此条目i指向vector[i]处的代码。
这主要是纯机械的,IDT项盲目地对应于向量
但是T_SYSCALL的1 (vs . 0)告诉CPU在系统调用期间启用中断,但不是在设备中断期间
    问:为什么在系统调用期间允许中断?
        可能系统调用只是用户请求内核帮忙,这时如果来一个硬件中断明显优先级更高
    问:为什么在中断处理期间(interrupt handling)禁用中断?
        中断处理的时候一般是一连贯的操作,如果被其他中断打断,可能导致系统崩溃,具体例子等后面遇到了再来添加把
vectors.S (由vectors.pl生成)
    首先push “error”槽在trapframe,因为h/w不推一些traps
    第二个push就是vector number
    这在trapframe中显示为tf->trapno

8.硬件如何知道使用什么堆栈来中断?
当它从用户空间切换到内核时
硬件定义的TSS(task state segment)允许内核配置(configure)CPU
   one per CPU
所以每个CPU可以运行不同的进程,在不同的堆栈上设置traps
   proc.c /调度器()
   每个CPU一个
vm.c / switchuvm ()
   告诉CPU使用什么内核堆栈
   告诉内核要使用什么页表

9.问:当trap到内核时,CPU应该保存什么eip ?
执行指令的eip ?
下一条指令的eip ?
假设trap是页面错误?
我觉得应该是引发trap的指令的下一条指令吧

9.Let’s talk about homework, which involves:
interrupts + system calls
challenges:
get it to work at all
maintain isolation (unfortunately, not easy way to test!)

10.alarmtest.c
   alarm(10, periodic)
   要求内核在此进程中每10次“滴答”调用周期()一次
   也就是说,这个进程消耗的CPU时间为10滴答
三个部分:
   添加一个新的系统调用
   计算程序运行时的滴答(计时器中断)
   内核对periodic()的“upcall”
对periodic()的调用是一个简化的UNIX信号

glue(胶合?) for a new system call (like date homework)
syscall.h: #define SYS_alarm 22
usys.S: SYSCALL(alarm)
   alarmtest.asm – mov $0x16,%eax – 0x16 is SYS_alarm
syscall.c syscalls[] table
sysproc.c sys_alarm()

break sys_alarm(比如homework)
在哪里
syscall如何知道哪个系统调用?
   内核堆栈上的trapframe保存了用户eax
   打印myproc () - > tf - > eax
sys_alarm在哪里找到参数、刻度和处理程序?
   on the user stack
   x/4x myproc()->tf->esp
处理程序值有意义吗?看看alarmtest.asm

现在,每当timer h/w 中断时,我们需要采取一些操作
减量ticksleft
如果过期
   向上调用处理程序(periodic())
   重置ticksleft

11.设备中断(device interrupts)就像INT和pagefault一样到达
h/w将esp和eip推送到内核堆栈上
s/w将其他寄存器保存到一个trapframe中
vector, alltraps, trap()

12.在没有实现的情况下执行trap
break vector32
   where
   print/x tf->eip
   print/x tf->esp
   x/4x tf->esp

此时用户程序在做什么?
tf - > eip在alarmtest.asm中
用户代码可能在任何地方被中断
   所以我们不能依赖任何关于用户堆栈的东西
   我们需要准确地恢复寄存器,因为程序没有保存任何东西

Q: how to arrange for upcall to alarm handler?
    call myproc()->alarmhandler() ?
   tf->eip = myproc()->alarmhandler ? 这个是对的
Q: how to ensure handler returns to interrupted user code? 应该是iret指令吧

the x86 h/w does not directly provide isolation
   x86 has many separate features (page table, INT, &c)
   it’s possible to configure these features to enforce isolation
   but isolation is not the default!

问:如果trap()没有检查CPL 3呢?
让我们试一下——似乎有效!
tf->cs&3 == 0怎么会产生于alarmtest?
让我们用(tf->cs&3)==0来强制执行这个情况
   并使alarmtest永远运行
   来自cpu 0的unexpected trap 14 eip 801067cb (cr2=0x801050cf)
内核.asm中的eip 0x801067cb是什么?
   trap()中的tf->esp = tf->eip。
发生了什么事?
   这是一个CPL=0到CPL=0的中断
   所以h/w没有交换栈
   所以它没有保存%esp
   所以tf->esp包含垃圾
更重要的一点是,中断可以在内核中发生(在xv6中,而不是在JOS中)

Q: what if another timer interrupt goes off while in user handler?
   works, but confusing, and will eventually run out of user stack
   maybe kernel shouldn’t re-start timer until handler function finishes

13.中断介绍了并发性(concurrency)
其他代码在我的代码之间运行
例如,我的代码是

  1. add %eax, %ebx
  2. add %ebx, %exc

问:其他代码可能在1和2之间运行吗? 是的!
对于用户代码来说可能没那么糟糕
      内核将以相同的状态恢复用户代码
      但是,alarmtest应该知道,periodic()可以在任意两条指令之间运行
对于内核代码可能很难
      中断处理程序可以更新我的代码可以观察到的状态

	my code:               interrupt:
	     %eax = 0
	     if %eax = 0 then        %eax = 1
	       f()

      f()可能被执行,也可能不被执行!
要使代码块具有“atomic”(原子性),请关闭中断
      cli()
      sti()
我们第一次遇到“并发性
我们将在讨论locking时会回到这一点

14.Interrupt evolution
中断过去相对较快;现在它们变慢了
      老方法:每个事件都会导致中断,简单的h/w,智能的s/w
      新方法:h/w在中断之前完成大量工作
有些设备每秒生成事件的速度超过一微秒
      例如,千兆以太网每秒可以传送150万个小数据包
中断的时间为一微秒
      save/restore state
      cache misses
      如果中断的速度超过每秒1微秒,该怎么办?

15.轮询(Polling):与设备交互的另一种方式
处理器旋转,直到设备需要关注
      如果设备很慢,就会浪费处理器周期
但如果设备速度快,价格也不贵
      不保存寄存器等。
如果事件总是在等待,则不需要一直提醒软件

Polling versus(对比) interrupts
对于高速设备,轮询比中断好
低速率设备的话,中断好些,例如键盘
      持续的轮询会浪费CPU
在轮询和自动中断之间切换
      当速率较低时中断(因为轮询会浪费CPU周期)
      当速率高时进行轮询(中断会浪费CPU周期)
更快地将中断转发到用户空间
      用于页面错误和用户处理的设备
      h/w直接交付给用户,w/o内核干预?
      更快地通过内核转发路径?
我们会在课程的后面看到很多这样的论题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值