x86: Triple fault on call instruction after switching page directory

1

I've been building my version of the xv6 OS, but just as I switch to a newly created page directory and try to call a function, it triple faults.

A lot of similar questions have been asked and usually the problem is that a page fault is not correctly handled, either because of incorrect page mapping or incorrect IDT.

In my case I've manually checked the mapping and it works, so I'm out of ideas what else can be broken. See below for details.

Here's where I am in the kernel (just switched CR3 to the new page table and about to call test_function):

   │0x801017ad <kernel_start+29>    call   0x80101040 <init_kernel_memory_range>
   │0x801017b2 <kernel_start+34>    call   0x801013c0 <init_global_kernel_page_dir>
   │0x801017b7 <kernel_start+39>    call   0x80101390 <switch_to_kernel_page_dir> 
  >│0x801017bc <kernel_start+44>    call   0x80101770 <test_function>

I can verify in gdb that the memory of test_function is accessible, so the mapping seems to be correct:

(gdb) x/10i test_function

0x80101770 <test_function>:          push   ebp
0x80101771 <test_function+1>:        mov    ebp,esp
0x80101773 <test_function+3>:        sub    esp,0x8
0x80101776 <test_function+6>:        lea    eax,ds:0x80101b00
0x8010177c <test_function+12>:       mov    DWORD PTR [esp],eax
0x8010177f <test_function+15>:       call   0x80101750 <panic>
0x80101784 <test_function+20>:       add    esp,0x8
0x80101787 <test_function+23>:       pop    ebp
0x80101788 <test_function+24>:       ret
0x80101789:  nop

I can also verify that the stack can be accessed:

(gdb) i r esp
esp            0x8010101c       0x8010101c

(gdb) x/10w 0x8010101c
0x8010101c:     0x80104024      0x80400000      0x00007bf8      0x90669066
0x8010102c:     0x90669066      0x8be58955      0xc35d0845      0x90909090
0x8010103c:     0x90909090      0x83e58955

The identity mapping of low addresses to physical that used to be in the previous page directory no longer exists, and that is intended (0x101770 is the physical address of test_function):

(gdb) x/10i 0x101770
0x101770:    Cannot access memory at address 0x101770

I have also manually verified that the addresses I care about are correctly translated using the page directory / page table into physical addresses. Yet when I finally call test_function, I get this in QEMU:

EAX=003ff000 EBX=00010094 ECX=003ff000 EDX=fe000000
ESI=00010094 EDI=00000000 EBP=80101024 ESP=8010101c
EIP=801017bc EFL=00000096 [--S-AP-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0000 00000000 00000000 00000000
GS =0000 00000000 00000000 00000000
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00007c60 00000017
IDT=     00000000 000003ff
CR0=80010011 CR2=00000040 CR3=003ff000 CR4=00000010
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
EFER=0000000000000000
Triple fault.  Halting for inspection via QEMU monitor.

IDT is not yet set up, but I'm not expecting any page faults yet.

Anything that I'm missing here? What else can cause a triple fault? Thanks.

x86
kernel
qemu
osdev
xv6
asked on Stack Overflow May 6, 2020 by Ivan Ivanov

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0