Triple fault upon call to extern function

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Triple fault upon call to extern function

Post by Benjamin1996 »

Hello everyone!
My problem is that when I try to execute an extern function call from my bootloader, my CPU triple faults and resets.
This is my 32 bit "protectedMode" function, located in bootloader.asm:

Code: Select all

[bits 32]
[extern kernel]
protectedMode:
    mov ax, 0x0010
    mov ds, ax ;Point ds to the code descriptor
    mov ss, ax ;Point ss to the code descriptor
    mov esp, 0x90000 ;Set the stack base to 0x90000
    call kernel
And this is kernel.asm:

Code: Select all

[bits 32]
[global kernel]
kernel:
    mov edi, 0xb8000 ;Point edi to the color video memory
    mov byte [edi + 800], 'K'
    mov byte [edi + 801], 0x0004 ;Display a red 'K' on a black background.
    jmp $  ;Hang the stub-kernel.
And this is my build.bat file:

Code: Select all

@echo off
nasm -f elf bootloader.asm -o bootloader.elf
nasm -f elf kernel.asm -o kernel.elf
ld -e kernel -o kernel.o kernel.elf
ld -Ttext 0x7c00 -o os.o bootloader.elf kernel.elf
objcopy -R .note -R .comment -S -O binary os.o os.bin
echo os.bin created!
rawwrite.exe
For testing, I'm using Bochs on Windows, and this is the message printed in bochsout.txt upon triple fault:

Code: Select all

00025746133i[CPU0 ] 0x000000000000fda8>> int1  : F1
00025746133e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
I would love some help :).

Best regards,
-Benjamin.
User avatar
qw
Member
Member
Posts: 792
Joined: Mon Jan 26, 2009 2:48 am

Re: Triple fault upon call to extern function

Post by qw »

You are using a code descriptor for the stack?
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Triple fault upon call to extern function

Post by Gigasoft »

According to the error message, the call instruction isn't the problem. Are you sure that everything is loaded at the right address? Use the X command in bochs to examine various addresses and check that they correspond to the data in os.bin. And check that the addresses used in the code are right.
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Triple fault upon call to extern function

Post by Benjamin1996 »

Gigasoft wrote:According to the error message, the call instruction isn't the problem. Are you sure that everything is loaded at the right address? Use the X command in bochs to examine various addresses and check that they correspond to the data in os.bin. And check that the addresses used in the code are right.
To be completely honest, I've never used Bochs debugger before, so could you please show me how to use the 'x' command properly?
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Triple fault upon call to extern function

Post by Gigasoft »

X examines a linear address, and XP a physical one. For example, to display 32 dwords starting at 0x7e00 physical, you'd write xp /32 0x7e00. To display 20 ASCII characters at 0x7e00, write xp /20cb 0x7e00. If you don't use byte format for characters, the characters will be reversed.

It's much easier to read the output if you enlarge the console before issuing the command. You can get more information on a command by typing "help" followed by the name of the command.
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Triple fault upon call to extern function

Post by Benjamin1996 »

Gigasoft wrote:X examines a linear address, and XP a physical one. For example, to display 32 dwords starting at 0x7e00 physical, you'd write xp /32 0x7e00. To display 20 ASCII characters at 0x7e00, write xp /20cb 0x7e00. If you don't use byte format for characters, the characters will be reversed.

It's much easier to read the output if you enlarge the console before issuing the command. You can get more information on a command by typing "help" followed by the name of the command.
Alright thanks. Well, to me it seems like everything is okay in terms of memory locations.
Do you think there's a possibility that I don't have A20 enabled correctly, and therefore haven't got access to more than 1MB of memory?
User avatar
Darwish
Posts: 21
Joined: Sat Oct 17, 2009 4:32 am

Re: Triple fault upon call to extern function

Post by Darwish »

Hi,
Benjamin1996 wrote: This is my 32 bit "protectedMode" function, located in bootloader.asm:

Code: Select all

[bits 32]
[extern kernel]
protectedMode:
    mov ax, 0x0010
    mov ds, ax ;Point ds to the code descriptor
    mov ss, ax ;Point ss to the code descriptor
    mov esp, 0x90000 ;Set the stack base to 0x90000
    call kernel
The regular x86 'call' instruction takes an %IP-relative address. If your code above is run from a different %IP than the one it's originally linked to, the relative address calculation becomes invalid.

I've faced such a situation while writing my kernel head, which was physical-addresses linked, but the portion of it calling the C entry point was run using a virtualized (different) %ip. A solution was getting rid of %IP-relativeness all together and use a near absolute indirect jump (opcode = FF):

Code: Select all

movq $kernel, %rax
jmpq %rax
Hope that helps ..
For latest news, please check my homepage and my blog.
—Darwish
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Triple fault upon call to extern function

Post by Benjamin1996 »

Darwish wrote:Hi,
Benjamin1996 wrote: This is my 32 bit "protectedMode" function, located in bootloader.asm:

Code: Select all

[bits 32]
[extern kernel]
protectedMode:
    mov ax, 0x0010
    mov ds, ax ;Point ds to the code descriptor
    mov ss, ax ;Point ss to the code descriptor
    mov esp, 0x90000 ;Set the stack base to 0x90000
    call kernel
The regular x86 'call' instruction takes an %IP-relative address. If your code above is run from a different %IP than the one it's originally linked to, the relative address calculation becomes invalid.

I've faced such a situation while writing my kernel head, which was physical-addresses linked, but the portion of it calling the C entry point was run using a virtualized (different) %ip. A solution was getting rid of %IP-relativeness all together and use a near absolute indirect jump (opcode = FF):

Code: Select all

movq $kernel, %rax
jmpq %rax
Hope that helps ..
Thanks a lot, but could you please show me the NASM (32 bit) equivalent to the code you posted?
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Triple fault upon call to extern function

Post by Gigasoft »

No, that's 64 bit. It should be:

Code: Select all

mov eax,kernel
jmp eax
However, this is just if the address of the jmp instruction is different from what it was when linking, and the address of the kernel label is the same. I doubt this is the case here. Remapping the kernel to a different address wouldn't work with the linking method you described.

Try setting a breakpoint on the protectedMode label. You should be able to generate a program listing that tells you where it is, if there are GCC and LD options for it. Then, step through the jmp instruction and check where it ends up. Check if this area contains the expected code.
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Triple fault upon call to extern function

Post by Benjamin1996 »

Gigasoft wrote:No, that's 64 bit. It should be:

Code: Select all

mov eax,kernel
jmp eax
However, this is just if the address of the jmp instruction is different from what it was when linking, and the address of the kernel label is the same. I doubt this is the case here. Remapping the kernel to a different address wouldn't work with the linking method you described.

Try setting a breakpoint on the protectedMode label. You should be able to generate a program listing that tells you where it is, if there are GCC and LD options for it. Then, step through the jmp instruction and check where it ends up. Check if this area contains the expected code.
Alright then Gigasoft, it seems that you were right. Remapping the kernel didn't work. But, I downloaded gdb.exe, and I typed "file bootloader.elf" and then "break protectedMode". This outputted:

Code: Select all

Breakpoint 1 at 0x6b
And after that I got lost trying to follow your instructions.. could you please be a little more specific?
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Triple fault upon call to extern function

Post by Solar »

Grab a GDB tutorial from somewhere in the internet, and experiment a bit with some normal (userspace) applications, until you are confident in your use of this tool.

This is not wasted time. I know you'd love to get on with your bootloader, but do take the time to get to know GDB.

Believe me, the kind of programming we do is very hard without the support of a decent debugger, and while GDB might have an air of the eighties about it, it's easily one of the most powerful debuggers available once you got to master it.
Every good solution is obvious once you've found it.
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Triple fault upon call to extern function

Post by Gigasoft »

I haven't used GDB, so I can only help you with using the debugger inside Bochs. When you link the program, you should use option -Map followed by a filename. For example, "-Map kernel.map". Then you look in this file for the symbol protectedMode (you may have to declare it to be global first). Then, in the Bochs debugger, you could enter "vb Segment:Offset", where Segment is the code selector you use when jumping to protectedMode, and Offset is the offset found in the map file. Then, enter the command "c", and it should stop at the correct location. Then, enter "s" to step until the jmp instruction has been executed. Note the value of EIP before and after the jmp, and check if the code jumped to is correct.
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Triple fault upon call to extern function

Post by Benjamin1996 »

Gigasoft wrote:I haven't used GDB, so I can only help you with using the debugger inside Bochs. When you link the program, you should use option -Map followed by a filename. For example, "-Map kernel.map". Then you look in this file for the symbol protectedMode (you may have to declare it to be global first). Then, in the Bochs debugger, you could enter "vb Segment:Offset", where Segment is the code selector you use when jumping to protectedMode, and Offset is the offset found in the map file. Then, enter the command "c", and it should stop at the correct location. Then, enter "s" to step until the jmp instruction has been executed. Note the value of EIP before and after the jmp, and check if the code jumped to is correct.
Alright, first of all, I've made a few changes to the 32 bit "protectedMode" function. So it now looks like this:

Code: Select all

[bits 32]
[global loadKernel]
loadKernel:
    mov ax, 0x0010
    mov ds, ax
    mov ss, ax
    mov esp, 0x90000
    jmp 0x0008:0x1000
Now the error message in "bochsout.txt" is:

Code: Select all

00014070914i[CPU0 ] 0x0000000047e87c5f>> (invalid)  : FFFF
00014070914e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
And this is one of the .text sections in "kernel.map":

Code: Select all

.text           0x00007c00      0x400
 *(.init)
 *(.text)
 .text          0x00007c00      0x200 bootloader.elf
                0x00007c6b                loadKernel
 .text          0x00007e00       0x15 kernel.elf
                0x00007e00                kernel
And now, this is the output of the final 's' command:

Code: Select all

(0) [0x00007c78] 0008:0000000000007c78 (unk. ctxt): jmp far 0008:00001000    ;
ea001000000800
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Triple fault upon call to extern function

Post by Gigasoft »

Why are you jumping to 0x1000? According to the map file, "kernel" is at 0x7e00. What you had initially should work, assuming that you have loaded the sectors to the correct addresses. Note that loading the sectors to address 0x1000 won't work, since the kernel assumes that it resides at 0x7e00. Try with "jmp kernel" and see what happens when you step through the jmp. EIP becoming 47e87c5f could mean that an exception occurs, and you haven't initialized the IDT. If you load IDTR with a limit of 0, Bochs should tell you which exception occurred. Maybe it would be easier to diagnose if you post the entire bootloader.asm or os.bin.
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Triple fault upon call to extern function

Post by Benjamin1996 »

Gigasoft wrote:Why are you jumping to 0x1000? According to the map file, "kernel" is at 0x7e00. What you had initially should work, assuming that you have loaded the sectors to the correct addresses. Note that loading the sectors to address 0x1000 won't work, since the kernel assumes that it resides at 0x7e00. Try with "jmp kernel" and see what happens when you step through the jmp. EIP becoming 47e87c5f could mean that an exception occurs, and you haven't initialized the IDT. If you load IDTR with a limit of 0, Bochs should tell you which exception occurred. Maybe it would be easier to diagnose if you post the entire bootloader.asm or os.bin.
Oops, my bad. - That's because I forgot to tell you that I loaded kernel.o into 0x1000.
Anyway, I've changed it (again :)), so here's the full "bootloader.asm":

Code: Select all

[bits 16]
boot:
    mov ax, 0x0000
    mov ds, ax
    call clearScreen
    call resetCursor
    mov si, loadingKernel
    call print
    call resetDiskSystem
    call enableA20
    call installGDT
    call protectedMode
protectedMode:
    cli
    mov eax, cr0
    or eax, 0x0001
    mov cr0, eax
    jmp 0x0008:loadKernel
installGDT:
    cli
    lgdt[GDT]
    sti
    ret
enableA20:
    mov ax, 0x2401
    int 0x0015
    jc enableA20
    ret
resetDiskSystem:
    xor ax, ax
    int 0x0013
    jc resetDiskSystem
    ret
print:
    lodsb
    cmp al, 0
    jz donePrinting
    mov ah, 0x000e
    int 0x0010
    jmp print
donePrinting:
    ret
resetCursor:
    mov ah, 0x0002
    mov bh, 0x0000
    mov dh, 0x0000
    mov dl, 0x0000
    int 0x0010
    ret
clearScreen:
    mov ax, 0x0600
    mov cx, 0x0000
    mov dx, 0x1950
    mov bh, 0x0007
    int 0x0010
    ret
[bits 32]
[global loadKernel]
loadKernel:
    mov ax, 0x0010
    mov ds, ax
    mov ss, ax
    mov esp, 0x90000
    jmp 0x0008:0x7e00
GDTNull: 
    dd 0
    dd 0 
GDTCode:
    dw 0x0FFFF
    dw 0
    db 0
    db 10011010b
    db 11001111b
    db 0
GDTData:
    dw 0x0FFFF
    dw 0
    db 0
    db 10010010b
    db 11001111b
    db 0
endOfGDT:
GDT: 
    dw endOfGDT - GDTNull - 1
    dd GDTNull
loadingKernel db "Loading kernel..", 0dh, 0ah, 0
times 510 - ($ - $$) db 0
dw 0xaa55                                                                                                                    
Full "kernel.asm":

Code: Select all

[bits 32]
[global kernel]
kernel:
    mov edi, 0xb8000
    mov byte [edi], 'K'
    mov byte [edi + 1], 0x0007
    hlt 
Full "build.bat":

Code: Select all

@echo off
nasm -f elf bootloader.asm -o bootloader.elf
nasm -f elf kernel.asm -o kernel.elf
ld -o kernel.o kernel.elf
ld -Ttext 0x7c00 -Map os.map -o os.o bootloader.elf kernel.elf
objcopy -R .note -R .comment -S -O binary os.o os.bin
echo os.bin created!
rawwrite.exe
Full "os.bin" opened in Notepad:

Code: Select all

¸  ŽØèU èG ¾|è5 è+ è  è è  ú Àf
   "Àêk| ú—|ûø$ÍrùÃ1ÀÍrúì< t´Íëõô· ¶ ² Íø ¹  ºP·ÍÃf¸ ŽØŽÐ¼  	 ê ~           ÿÿ   šÏ ÿÿ   ’Ï  |  Loading kernel..
                                                                                                                                                                                                                                                                                                                                               Uª¿ € ÆKÆGôÿÿÿÿ    ÿÿÿÿ                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
Some of "os.map":

Code: Select all

Adressen på sektionen .text sat til 0x7c00
LOAD bootloader.elf
LOAD kernel.elf
                0x000001f0                . = SIZEOF_HEADERS
                0x00001000                . = ALIGN (__section_alignment__)

.text           0x00007c00      0x400
 *(.init)
 *(.text)
 .text          0x00007c00      0x200 bootloader.elf
                0x00007c6b                loadKernel
 .text          0x00007e00        0xd kernel.elf
                0x00007e00                kernel
And finally the error message in "bochsout.txt":

Code: Select all

00014073431i[CPU0 ] 0x000000000000fda8>> int1  : F1
00014073431e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
Now, the funny thing is that it runs without crashing in Microsoft Virtual PC and on real hardware, BUT, even though it doesn't crash, it doesn't execute the "kernel" function..??
Post Reply