课后作业4.3:段页式内存管理

第1关:第一次页故障

本关任务:系统的第一次页故障发生时:

1.当时正在执行几号进程? 正在访问的线性地址是多少?

2.该线性地址当时对应的页表项是什么?被映射到的物理地址是什么?

3.该页故障处理完后,该线性地址对应的页表项是什么?被映射到的物理地址是什么?

4.引发这次页故障的指令地址是什么?

5. main 函数中的 fork 系统调用的陷入指令的地址是多少?

由于需要在bochsdbg模式下确定进程号,所以现在gdb模式跟踪到schedule函数,然后查看当前所有进程的进程控制块地址,并确定其进程号

可见 0 号进程和 1 号进程的进程控制块地址分别是 0x1bec0 和 0xfff000 。现在查看 current 的地址:

如何跟踪到第一次页故障发生

页故障处理函数是 page_fault ,首先查询这个函数的地址,然后在 bochsdbg 中在该地址设断点,并跟踪到该断点的第一次出现即可。所以在gdb模式查看page_cault函数地址

在bochsdbg模式跟踪到page_fault函数,并查看当前进程号

可以看到是1号进程

如何知道是对哪个线性地址的访问引发了页故障

在页故障发生时,CR2 寄存器中记录了此地址,可以用 creg 命令查看。

可以看到正在访问的线性地址是多少0x402574c

观察该线性地址对应的页表项和映射到的物理地址

页表项是0x25065,所以映射到的物理地址是0x2574c

通过u命令进行反汇编,找到iret指令并跟踪到其地址

此时页故障处理完成,再次查看上面线性地址对应的页表项和映射到的物理地址

通过一步s命令就可以查看引发这次页故障的指令地址。这里需要注意的是:Page fault是fault类异常,其断点和恢复点是同一条指令!

对于main 函数中的 fork 系统调用的陷入指令的地址,我们只需要在gdb模式跟踪到fork函数然后进行反汇编就可以看到

这里为了确保准确,先跟踪到fork函数的上一行,然后通过n命令步进,然后再进行反汇编

最终答案:

系统的第一次页故障发生时:

1.当时正在执行几号进程?(1)正在访问的线性地址是多少?(0x402574c)

2.该线性地址当时对应的页表项是什么?(0x25065)被映射到的物理地址是什么?(0x2574c)

3.该页故障处理完后,该线性地址对应的页表项是什么?(0xffd007)被映射到的物理地址是什么?(0xffd74c)

4.引发这次页故障的指令地址是什么?(0x690a)

5. main 函数中的 fork 系统调用的陷入指令的地址是多少?(0x6908)

第2关:父子进程间的共享内存通信实现

本关任务:改写版本 1.3 内核,使得 0 号进程顺序循环输出小写字母 a、b、c  . . . ,每输出一个字母就执行 pause 系统调用; 1 号进程的行为类似,只不过将小写变为大写;同时要求两个进程输出的字符是关联递增的,即如果 0 号进程上一次输出了字符a,那么这一次如果是 1 号进程运行,那它应该输出字符B,反之亦然,运行画面如下图所示。(要求还是使用 int 0x81 输出字符,且不能修改 int 0x81 的实现方式)

最终答案:

  1. @@ -59,6 +59,7 @@
  2.  extern void task0(void);    /* wyj, 2 lines */
  3.  extern void task1(void);
  4.  extern void output_char(char c);
  5. +int next_char = 0;  /* the next char to be outputed, in range [0, 25) */
  6.  /*
  7.   * This is set up by the setup-routine at boot-time
  8. @@ -108,10 +109,6 @@
  9. static long main_memory_start = 0;
  10. struct drive_info { char dummy[32]; } drive_info;
  11. -
  12. -
  13. -static int mynext = 0;  /* the next char to be outputed, in range [0, 25) */
  14. -
  15. void main(void)        /* This really IS void, no error here. */
  16. {            /* The startup routine assumes (well, ...) this */
  17. /*
  18. @@ -148,13 +145,13 @@
  19.      sti();
  20.      move_to_user_mode();
  21. +    next_char = 0;
  22.      if (!fork()) {        /* we count on this going ok */
  23.          (void)mysignal(SIGALRM, SIG_IGN);
  24.          for(;;) {
  25. -            if (mynext < 7) {
  26. -                output_char('A' + mynext);
  27. -                mynext++;
  28. -            }
  29. +            output_char('A'+next_char++);    /* wyj */
  30. +            if (next_char >= 26)
  31. +                next_char = 0;
  32.              alarm(1);
  33.              pause();
  34.          }
  35. @@ -168,10 +165,9 @@
  36.   * task can run, and if not we return here.
  37.   */
  38.      for(;;) {
  39. -        if (mynext < 7) {             /* wyj */
  40. -            output_char('a' + mynext);
  41. -            mynext++;
  42. -        }
  43. +        output_char('a'+next_char++);    /* wyj */
  44. +        if (next_char >= 26)
  45. +            next_char = 0;
  46.          pause();
  47.      }
  48. }

修改linux/mm/memory.c

  1. @@ -130,7 +130,7 @@
  2.      invalidate();
  3.      return 0;
  4.  }
  5. -
  6. +extern int next_char;
  7.  /*
  8.   *  Well, here is one of the most complicated functions in mm. It
  9.   * copies a range of linerar addresses by copying only the pages.
  10. @@ -175,7 +175,9 @@
  11.              this_page = *from_page_table;
  12.              if (!(1 & this_page))
  13.                  continue;
  14. -            this_page &= ~2;
  15. +            if ((this_page & 0xfffff000) !=
  16. +                (((unsigned int)&next_char) & 0xfffff000))
  17. +                this_page &= ~2;
  18.              *to_page_table = this_page;
  19.              if (this_page > LOW_MEM) {
  20.                  *from_page_table = this_page;

猜你喜欢

转载自blog.csdn.net/z671514087/article/details/128387737