Chinaunix首页 | 论坛 | 博客
  • 博客访问: 56681
  • 博文数量: 13
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 130
  • 用 户 组: 普通用户
  • 注册时间: 2015-04-26 15:04
文章分类

全部博文(13)

文章存档

2015年(13)

我的朋友

分类: LINUX

2015-05-13 20:56:19

  昨天晚上在kernel.c里开了一个ring3进程,测试,在bochs里显示双重页错误。
  早上起床,开始调试。从这个bug开始。
  首先,确定这到底是不是“双重页错误”。因为自己的do_page_fault写的比较弱,怀疑它判断的不准。果然,do_page_fault里是每次进入时,作pgerr_count++,在返回前却没有pgerr_count--。
  纠正过来,这下屏幕疯狂的输出页错误信息。这种信息是do_page_fault运行时内部pirntf的,打印error_code,错误前夕esp,eip等等。细看看,满屏的信息,都是同一条信息不断的重复,应该是这个缺页错误,没有被do_page_fault解决,返回用户空间后,立刻又陷进来。
  我没有根据这些信息,去分析这个页错误是怎么回事。因为我现在还不信任这些信息,从page_fault入口,到error_code公共异常部分,再到do_page_fault,都是昨天才写的,没有测试过。
  打印的信息里,esp是0xbfffffbc,是接近3G地方,不算离谱,eip是0xc0030c31,内核的代码区是从0xc0030400开始的,也不算离谱。再看出错码,0x11202,虽然我记不清page fault出错码的格式了,但它的高若干位都是保留的,不该有这么大。一查,intel16位的页错误码,只用了低三位,剩余的都是保留的。do_page_fault收到的出错码应该错了。
  找到提取出错码的汇编部分,原来是push [eax+REGS_ERR_CODE_OFFSET],这句引用的REGS_ERR_CODE_OFFSET定义错了,应该是equ 11,不小心数成了12.
  纠正过来,运行,系统spin住了,显示的不再是page not exsit error,而是page protection error。再看出错码,是0x5。表明是在用户级别下,读取系统页引发的错误。
  这时候还是很兴奋的。因为之前的那种页错误,就是从do_page_fault出去又立刻陷回来那种。我没什么思路。
  现在是页面保护异常了。
  很快想到,是进程运行在ring3级别,进程体的代码确实内核的函数,这样,eip在系统页面上走,当然会触发页级别的保护异常。
  想到这儿,我看了看进程体函数再内核中的地址,0xc00c0345,再看看do_page_fault的打印信息,果然,出错的指令地址是0xc00c0345。就是说,进程刚启动,eip刚碰到0xc00c0345,就引发了页保护异常。
  到boot.asm里,把内核页目录和页表全初始化成用户页面。
  再运行,出错码从0x5变成了0x7,这应该是另一处新的页错误,多出来的2,表示是写操作引起的。
  先可以高兴一下,因为这应该是另一处页错误,刚才的页错误已经解决了。
  这个错误是,用户模式下,写了系统页。
  立刻想到是c函数里,经典的第一条指令,push ebp。
  看看出错地址,看看出错地址,还是0xc00c0345,那就看看那儿的指令序列。果然,第一条是push ebp。
  内核里,用户进程的堆栈本来就是没有分配物理页的,就等着它触发缺页错误时,分配给它。
  可怎么触发了页保护异常呢?
  先不管,先把进程体对应的usr_func函数,从kernel.c挪到kernel.asm里,用汇编实现,只有一条语句:jmp $。
  运行,刚才的错误信息消失了。屏幕上是进程调度的打印输出,表明进程在切换和调度,虽然不那么正常。
  但还是可以松口气,因为确定是堆栈push引发的那个页错误。
  ...    ....
  这里省略一段,因为又发现了schedule函数的bug,花了至少有两个小时吧。
  回来还是要面对那个页错误,为什么是保护故障呢?想了一会儿,观念几乎被颠覆,心想,用户界别碰到空的page direcotry entry或是table entry,首先触发的应该是页保护机制吧。
  于是把进程页目录表的前(3G/4M)个entry,全设置称PG_USU,即用户级别。
  但错误依旧。
  折腾了很久,最后发现是之前代码的遗留bug,之前已经把堆栈起始的一个页映射了物理页,但映射的是PG_USS,系统级别。又因为这段旧代码是在进程创建流程的靠后部分,导致我前面怎么改动页目录,都会被它覆盖。
  直接把这段代码删掉就好了。
  用户级别,碰到空白的(就是全0)的page dir entry或table entry,是触发缺页故障的。这一点要牢记,当时如果很坚定,估计解决的会快一些,至少不会想着往entry上添PG_USU位。

--------------今天的tips--------
1,bochs的break命令,设置的是物理地址断点。
2,今天内核已经出现了bug不可复现的情况。不知道跟bochs有多大关系。目前使用的是slowdown选项,用其它的选项none,realtime,似乎都有问题。全部注释也有问题。


阅读(1535) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~