2013-05-05 31 views
1

我目前正在开发一个内核,并在执行系统调用时遇到一个神秘的问题。我写这样的0x80th中断处理程序:中断处理程序中的奇怪行为

sys_call_s: 
    pushad 
    call sys_call 
    popad 
    iret 

“sys_call”是执行实际工作的C函数的名称。问题是:执行“int 0x80”的下一条指令时出现三重故障。例如,我在执行下面的程序的第三行时遇到了错误,最后bochs会自行重置。

abc: mov eax,0    ; 0 means system call get_pid() 
    int 0x80 
    mov [pid_father],eax ; this is the instruction caused bochs to triple fault 
    mov eax,1    ; 1: fork() 
    int 0x80 
    jmp $ 

pid_father: dd 0 

更strangly,当我以“RET”的“IRET”指令时,程序工作正常,在“JMP $”旋本身。

有没有人有任何想法,为什么我得到这个问题?

现在我认为这个问题是由堆栈指针的错误地址引起的。我为这个过程配了一个页面,这个页面的物理地址是0x401000,线性地址是0x800000(8M)。我已将此进程的堆栈指针设置为0x800ff0,但每次在bochs中使用“print-stack”命令时,输出为:“物理地址不可用于线性0x00801000”。我该如何解决它?

现在我发现我无法在这个过程中访问数据。例如,当我在“int 0x80”之前放置“mov [pid_father],eax”时,bochs会重置其自身。为什么会发生?

回答

1

我认为你需要显示你的GDT和DS寄存器和分页表的内容。如果您在该行中发现了没有任何其他代码的三重错误,那么这意味着访问[pid_father]是问题。数据段无效,或页面无效或标记为只读,这会导致GPF或页面错误异常。 GPF或页错误异常失败(可能出于同样的原因或不同的原因),这会导致出现双重故障异常,这又会导致CPU出现三重故障并重置失败。

Bochs通常很好(从内存中)打印出为什么会出错。您可能希望稍微向上滚动历史记录并查找引发的第一个异常。

+0

感谢您的提示,斯图尔特。 – 2013-05-05 07:04:13

+1

问题位于页面表中。我没有在相应的页表项中设置可写标志。所以,每次我写这个页面时,我都会遇到保护错误。 当使用指令“ret”从中断处理程序返回时,代码段的选择器是0x10,它是内核的代码选择器,并且此段中的代码有权读/写任何页面的访问权。这解释了为什么第一个过程beheaviors用“ret”代替“iret”指令后。 – 2013-05-05 07:15:11

+0

真的吗?我认为页面保护会覆盖选择器保护,所以如果页面表被标记为只读,那么不管当前代码段如何,页面都是只读的。顺便说一句 - 你没有提到你启用了分页功能。这将是一件有用的事情。 – Stewart 2013-05-05 19:20:03