PA3.1 实现自陷操作

实现自陷操作

  • 操作系统中的等级制度
  • 陷发自陷操作
  • 保存上下文
  • 事件分发和恢复上下文

操作系统中的等级制度

首先我们需要知道的是计算机中的指令分为特权指令和非特权指令。其中特权指令大多是和操作系统底层相关的操作,如果任何程序都可以使用特权指令,那么个操作系统也就距离崩溃不久了。实验指南中用了一个银行取钱的例子来帮助大家理解什么操作系统中的等级制度。

PA3.1 实现自陷操作_第1张图片
这里我话了一个简单的图片来说明如何访问非特权指令和特权指令。

  1. 当一个程序需要访问非特权指令时可以直接访问。
  2. 当一个程序需要访问特权指令时,需要产生中断进行核心态,然后由操作系统调用特权指令。

陷发自陷操作

首先我们需要根据操作指南介绍的定义HAS_CTE宏,定义了以后Nanos-lite会在panic()前调用_yield()来触发自陷操作。
此时我们先运行下,看下结果
PA3.1 实现自陷操作_第2张图片
可以看到0f指令没有实现,查看i386手册,可以看到这个指令是LGDT/ LIDT。接下来可以根据描述 Load m into IDTR来实现这个指令。
PA3.1 实现自陷操作_第3张图片
PA3.1 实现自陷操作_第4张图片
首先来分析lidt指令,lidt指令对作用是加载中断描述符,操作是将源操作数中的数值加载到中断描述符表格寄存器 。

make_EHelper(lidt) {
 // TODO();
    //   IF OperandSize = 16
    //      THEN IDTR.Limit:Base := m16:24 (* 24 bits of base loaded *)
    //         ELSE IDTR.Limit:Base := m16:32
    rtl_li(&t0,id_dest->addr);
    rtl_li(&cpu.idtr.limit, vaddr_read(t0,2));
    rtl_li(&cpu.idtr.base, vaddr_read(t0+2,4));
    print_asm_template1(lidt);
} 

接下来分析raise_intr()函数,这个函数的作用是用来模拟中断操作,也就是这段的描述:

  1. 依次将EFLAGS, CS(代码段寄存器), EIP寄存器的值压栈
  2. 从IDTR中读出IDT的首地址
  3. 根据异常号在IDT中进行索引, 找到一个门描述符
  4. 将门描述符中的offset域组合成目标地址
  5. 跳转到目标地址
    这部分代码就不贴出来了,大家按照描述实现即可,其中要注意的是判断门操作符的标志符来区分操作是否有效。
    实现后进行make run,结果如下:
    PA3.1 实现自陷操作_第5张图片
    (这个部分我当时不知道是否正确,只能进一步继续操作。)更新,这个部分操作错误了,忘记在exec.c中添加操作指令。

保存上下文

这个部分没什么特别难实现的,按照说明一步一步操作即可。
按步骤操作

首先需要注意的是pusha压栈过程是:

栈顶
edi
esi
ebp
esp
ebx
edx
ecx
eax

然后是压入错误吗和异常信号的操作:

栈顶
eflags
cs
eip
err

!!!注意,上面那个部分很重要,很重要。用来做什么的,仔细读讲义~
实现完成后触发一个未处理的1号事件。
PA3.1 实现自陷操作_第6张图片

事件分发和恢复上下文

这个地方我卡住的原因是因为不知道tf->riq代码的含义,通过谷歌查询到 :

  1. YIELD 0x81
  2. SYSCALL 0x80(后面发现PA3.2中介绍了这个两个代码的含义)
    然后按照要求实现各个命令即可啦~
    PA3.1 实现自陷操作_第7张图片

中识别出自陷事件_EVENT_YIELD, 然后输出发现yield事件,并且最终出发了main()函数中的Panic()函数。
做完以后,发现是HIT BAD TRAP at eip = 0x00100032,这个地方应该是还有问题。继续排查。(哈哈,原来是实现了PA3.2才会出现HIT GOOD TRAP!!

git log截图

你可能感兴趣的:(PA实验)