update lab1_report, solve some former problems.

This commit is contained in:
Shine wOng
2019-11-17 16:23:51 +08:00
parent 50dfbb483e
commit 0c7f65cbd7
2 changed files with 15 additions and 6 deletions

View File

@@ -23,7 +23,7 @@ BIOS -> 加载程序(Bootloader) -> 操作系统
+ 这是因为操作系统的种类复杂有许多不同的操作系统他们各自具有不同的文件系统。BIOS的内容是出厂固化的不可能使之可以分辨所有的操作系统。让BIOS的那点程序分辨不同操作系统的文件系统并将其加载到内存中会使BIOS的设计非常复杂以至于BIOS自己就成为了一个操作系统。
+ 而Bootloader并不属于任何的操作系统不属于任何的磁盘扇区而是存在于一个叫引导扇区的地方其中一个扇区大小512字节因此Bootloader也是512字节大小。它可以具有独立于操作系统的编码方式因此可以被BIOS识别。故可以先将Bootloader读入内存Bootloader加载操作系统。
+ 而Bootloader并不属于任何的操作系统不属于任何的磁盘扇区而是存在于一个叫引导扇区的地方其中一个扇区大小512字节因此Bootloader也是512字节大小。它可以具有独立于操作系统的编码方式因此可以被BIOS识别。故可以先将Bootloader读入内存Bootloader加载操作系统。
此外我们看到BIOS在加载Bootloader的过程中已经有用到一些操作系统的功能他们包括

View File

@@ -331,7 +331,7 @@ seta20.2:
保护模式就不一样了因为地址空间已经变成了32位而段寄存器的长度还是16位直接用段寄存器的值来索引内存的某一个段感觉有点寒碜啊。这时候段寄存器的值已经不是某一个地址了而是用来索引段表中某一项的段选择子(segment selector)
我们知道段表的结构是一个线性表里面每一项包括8字节其中32位指该段在内存中的起始地址。段表中至多可以有8192(2^13)项也就是允许同时存在8192个段。此时CS寄存器中的值只是对段表这个线性表的一个索引表示当前选择的是段表中的第几个段。
我们知道段表的结构是一个线性表里面每一项包括8字节其中32位指该段在内存中的起始地址。段表中至多可以有8192(2^13)项也就是允许同时存在8192个段。此时CS寄存器中的值只是对段表这个线性表的一个索引表示当前选择的是段表中的第几个段。
由于至多有8192个段因此可以只用CS中的高13位就足以指定段表中的任意一个段。还有低3位是用来表示一些控制信息
@@ -435,7 +435,7 @@ protcseg:
# Set up the protected-mode data segment registers
```
其中,`$PROT_MODE_CSEG`就是段表中代码段的偏移即0x8, `$protcseg`则为下一条指令的偏移地址。这样Bootloader才算完全实现了从实模式进入到保护模式。
其中,`$PROT_MODE_CSEG`就是段表中代码段的偏移即0x8, `$protcseg`则为下一条指令的偏移地址。这样Bootloader才算完全实现了从实模式进入到保护模式。那么这条长跳转指令本身是如何被找到的呢我的想法是由于CPU的流水线机制导致在进入保护模式前这条指令被预取了。
## 练习4分析bootloader加载ELF格式的OS的过程。
@@ -745,7 +745,16 @@ asm volatile("movl (%0), %%ebp": "r"(ebp))
这个思路我本来觉得挺好的,但是在更新`ebp`后我之前定义的局部变量就都失效了,就是说具有一个未定义的值。因此,也印证了各个变量的确是存储在当前函数的局部堆栈里面,一旦修改了`ebp`,就索引不到这些变量了。
+ 还应该注意到最后两句内联汇编的次序。之前也说过,`ebp + 4`的值并不是与当前`ebp`对应的`eip`,而是上层函数的返回地址。因此,需要先读取这个`eip`,再更新`ebp`,才能使两者对应起来。
+ 感觉题目给的示例输出有问题啊,似乎是直接指定了函数的参数固定输出四个。而我的代码是根据`debuginfo`给出的函数参数个数信息,逐个进行打印的。
+ 最后一行的数值?至今没看懂是什么意思。
+ 关于最后最后一行的数值,可以追溯到`bootasm.S`中对`esp`和`ebp`的初始化工作:
```asm
# Set up the stack pointer and call into C. The stack region is from 0--start(0x7c00)
movl $0x0, %ebp
movl $start, %esp
call bootmain
```
可以看到,初始的`esp`被设置为了`bootloaded`的起始地址,亦即`0x7c00`。最后进行了一次函数调用`call bootmain`,首先是硬件将`eip`压栈,此时`esp = 0x7bfb`,随后是编译器添加的将`ebp`压栈,然后令`ebp = esp`,此时`ebp = esp = 0x7bf8`,这也就是函数调用堆栈中的第一个`ebp`,因此对函数调用过程的追踪终止于此,可以看到`ebp`的值和这里的分析是一致的。
## 练习6完善中断初始化和处理 (需要编程)
@@ -765,7 +774,7 @@ asm volatile("movl (%0), %%ebp": "r"(ebp))
为了要能描述中断服务程序的入口地址,门描述符显然应该具有
+ 段描述符2个字节。这样查到段描述符后,显然还需要查段表,才能获得入口程序的物理地址。
+ 段选择子2个字节。这样查到段选择子后,显然还需要查段表,才能获得入口程序的物理地址。
+ 偏移量4个字节
除此以外,还需要一些控制字,来描述优先级,中断类型(硬中断,异常,陷入)等信息。其具体结构如下:
@@ -947,4 +956,4 @@ trap_dispatch(struct trapframe *tf) {
可以看到,在`trap_dispatch`里面才是进行实质的中断处理,主要是判断当前中断的中断号(存储在`trapframe`结构体中),我觉得应该可以用其他信息,来进行中断服务例程。
关于这个程序,唯一想说的还是那个全局变量`ticks_count`,我将它定义在了`init.c`里面,但是总感觉不够优雅,我也不知道应该怎么优雅...
关于这个程序,唯一想说的还是那个全局变量`ticks_count`,我将它定义在了`init.c`里面,但是总感觉不够优雅,我也不知道应该怎么优雅...结果后来发现老师已经定义好了一个`ticks`全局变量。