MIT6.828-LAB1 : PC启动 (3)

  在运行boot loader时,boot loader中的链接地址(虚拟地址)和加载地址(物理地址)是一样的。但是当进入到内核程序后,这两种地址就不再相同了。

  操作系统内核程序在虚拟地址空间通常会被链接到一个非常高的虚拟地址空间处,比如0xf0100000,目的就是能够让处理器的虚拟地址空间的低地址部分能够被用户利用来进行编程。

  但是许多的机器其实并没有能够支持0xf0100000这种地址那么大的物理内存,所以我们不能把内核的0xf0100000虚拟地址映射到物理地址0xf0100000的存储单元处。

  这就造成了一个问题,在我们编程时,我们应该把操作系统放在高地址处,但是在实际的计算机内存中却没有那么高的地址,这该怎么办?

  解决方案就是在虚拟地址空间中,我们还是把操作系统放在高地址处0xf0100000,但是在实际的内存中我们把操作系统存放在一个低的物理地址空间处,如0x00100000。那么当用户程序想访问一个操作系统内核的指令时,首先给出的是一个高的虚拟地址,然后计算机中通过某个机构把这个虚拟地址映射为真实的物理地址,这样就解决了上述的问题。那么这种机构通常是通过分段管理,分页管理来实现的。

  在这个实验中,首先是采用分页管理的方法来实现上面所讲述的地址映射。但是设计者实现映射的方式并不是通常计算机所采用的分页管理机构,而是自己手写了一个程序lab\kern\entrygdir.c用于进行映射。既然是手写的,所以它的功能就很有限了,只能够把虚拟地址空间的地址范围:0xf0000000 - 0xf0400000,映射到物理地址范围:0x00000000 - 0x00400000上面。也可以把虚拟地址范围:0x00000000 - 0x00400000,同样映射到物理地址范围:0x00000000~0x00400000上面。任何不再这两个虚拟地址范围内的地址都会引起一个硬件异常。虽然只能映射这两块很小的空间,但是已经足够刚启动程序的时候来使用了。

4.1 Exercise 7

问题1:使用Qemu和GDB去追踪JOS内核文件,并且停止在movl %eax, %cr0指令前。此时看一下内存地址0x00100000以及0xf0100000处分别存放着什么。然后使用stepi命令执行完这条命令,再次检查这两个地址处的内容。确保你真的理解了发生了什么。

问题2: 如果这条指令movl %eax, %cr0并没有执行,而是被跳过,那么第一个会出现问题的指令是什么?我们可以通过把entry.S的这条语句加上注释来验证一下。

对于第一个问题。其实只要在0x100000C这个地方打一个断点(我们前面其实知道这个地址就是内核的入口地址

image-20210620161032107

然后通过断点看一下就可以。发现这个时候还是不一样的

我们这个时候发现就变成了一样的。说明这个时候已经完成了从物理地址到虚拟地址到映射

第二个问题的答案显然就是会出现段错误。因为这一行代码注释之后,就没有办法开启虚拟地址了。不得不说这样的实验设计蛮棒的

4.2 Exercise 8

这里要在/lib/printfmt.c这个下做一些改动

搞明白print.c的调用链cprintf -> vcprintf -> vprintfmt -> putch -> cputchar

// (unsigned) octal case 'o': // Replace this with your code. // putch('X', putdat); // putch('X', putdat); // putch('X', putdat); num = getuint(&ap,lflag); base = 8; goto number; break; 4.3 Exercise9

判断一下操作系统内核是从哪条指令开始初始化它的堆栈空间的,以及这个堆栈坐落在内存的哪个地方?内核是如何给它的堆栈保留一块内存空间的?堆栈指针又是指向这块被保留的区域的哪一端的呢?

前面有分析到main.c的最后一行代码是要进入Entry.S.所以直接进入entry.s中

从注释里面可以看到堆栈指针应该是在这两行设置的

# Clear the frame pointer register (EBP) # so that once we get into debugging C code, # stack backtraces will be terminated properly. movl $0x0,%ebp # nuke frame pointer # Set the stack pointer movl $(bootstacktop),%esp

这里通过断点找到这两行到底在干什么。这里的esp寄存器就是栈指针寄存器。而ebp寄存器是栈帧的基地址指针

这里把0xf0110000赋给esp这个寄存器。就表示我们的栈是从这个地址开始。那么他的大小为多少那

bootstack: .space KSTKSIZE .globl bootstacktop

这几行代码就为他制定了大小大小为32kb。因此整个栈的地址区间就为 0xf0108000-0xf0110000的范围。

4.4 Exercise 10

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyxszw.html