OSDev.org

The Place to Start for Operating System Developers
It is currently Sat Sep 21, 2019 7:14 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 15 posts ] 
Author Message
 Post subject: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 9:33 am 
Offline

Joined: Sun Jun 02, 2019 5:05 am
Posts: 7
Hello all,

After trying to find where is the problem in my interrupt handler for weeks, i come here to ask for you help.
I currently try to write an x64 os for UEFI (using microsoft x64 abi as i crosscompile with mingw)

My os load, prepare the graphics driver for console use, exit UEFI world and the kernel function take the lead.
I then load a new gdt and idt.

As expected when i activate the interrupt, irq 0 triggers.
My asm handler is called then the c handler(i achieve to display the registers for debug purpose).

But when the code exit the interrupt asm handler (reach iretq instruction), int 13 is triggered, i suppose because i messed up with something, maybe the stack.
I also tried to put a blank tss, to solve the problem without success.

I attached the interrupt part of the code but if you need more part i'll write it directly (i could only attach 3 files)

Thanks in advance :)


Attachments:
idt.h [2.74 KiB]
Downloaded 3 times
idt.c [7.3 KiB]
Downloaded 4 times
interrupt.s [2.49 KiB]
Downloaded 7 times
Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 9:42 am 
Offline

Joined: Sun Jun 02, 2019 5:05 am
Posts: 7
I attached a small capture of the output i could retrieve from the registers


Attachments:
Capture du 2019-08-03 17-34-26 2.png
Capture du 2019-08-03 17-34-26 2.png [ 110.36 KiB | Viewed 454 times ]
Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 10:15 am 
Offline
Member
Member

Joined: Thu Aug 13, 2015 4:57 pm
Posts: 369
Have you checked this:
https://wiki.osdev.org/Exceptions#General_Protection_Fault

It has a list of common reasons, as well as a note about the error code.

Run your code in qemu or bochs, set a breakpoint in the iretq that's causing your problem and check what the stack looks like and check the intel manual that describes what iretq does.

Often people try to avoid using debuggers, because they haven't learned to how to use them, in practice with osdev you're going to need to learn anyway, so might as well start =)


Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 12:35 pm 
Offline

Joined: Sun Jun 02, 2019 5:05 am
Posts: 7
Thank you LtG for taking time to help me :)

I retrieved the error code of the interrupt and i have 0x28 which correspond to gtd[5] i suppose.
I now know that it is a segment error :)

I currently set the following for my gdt :

Code:
gdt_set_gate(0, 0, 0, 0, 0);                // Null segment
    //0xAF instead of 0xCF because we are in 64bit
    gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xAF); // Code segment
    gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xAF); // Data segment
    gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xAF); // User mode code segment
    gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xAF); // User mode data segment


i do not understand why i would have cs=28 when the interrupt 0 trigger and why it would try to return to it when i do iretq.
gdt[5] could be a tss put in place by the UEFI but as i flush the gdt again, it thought that the gdt was replaced by the new one (and so only have my segments). I tried with or without a tss as gdt[5] without any change in the behaviour

For the debugger, i can use QEMU but i have different behaviour (the stacks seems moved as the parameters send to the handlers is slightly shifted from some 64bit variable) and with the remote debugging of gdb the breakpoints are not triggered.


Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 1:08 pm 
Offline
Member
Member

Joined: Thu Aug 13, 2015 4:57 pm
Posts: 369
Is GDT[5] valid (check what's there in the VM software or the debugger)? Is it supposed to be valid?

It sounds like it's not supposed to be used, and that it's invalid, and thus _can't_ be used. If that's the case, then it would have caused an exception when you used it, prior to the interrupt. Given that that is not the case, then it seems to me, that it only gets used when iretq is issued.

Iretq switches to the segment it gets from the stack --> you're probably messing up your stack.


Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 1:12 pm 
Offline
Member
Member

Joined: Thu Aug 13, 2015 4:57 pm
Posts: 369
LtG wrote:
Iretq switches to the segment it gets from the stack --> you're probably messing up your stack.


Just to clarify, you're probably messing up your stack _prior_ to iretq, somewhere in the ISR or any code you might call from the ISR.

Do you call C code from the ISR? If so, check you are doing it correctly:
https://wiki.osdev.org/Calling_Conventions


Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 1:25 pm 
Offline

Joined: Sun Jun 02, 2019 5:05 am
Posts: 7
For iretq, i though that it would just bring back cs, but you are right, it would make more sens that cs is saved on the stack and brought back as it is pop by iretq. :)

GDT[5] is not supposed to exist at this point i suppose (tss is not put in place and i set only gdt until 4).
I do not understand why the code that is first interrupt by int0 has a cs of 28 (gdt[5]), a legacy from UEFI maybe ? UEFI set a first gdt and idt from what i understood.


Attachments:
gdt_asm.s [345 Bytes]
Downloaded 4 times
gdt.h [1.58 KiB]
Downloaded 3 times
gdt.c [1.98 KiB]
Downloaded 4 times
Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 2:37 pm 
Online
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 482
Can you put your entire project on github?

I noticed in gdt_asm.s that your gdt_flush doesn't attempt to set CS so CS will contain whatever selector EFI was using when it set up its GDT originally. You also don't seem to reload the other segment registers when you reload so they too will be using whatever EFI set up.


Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 2:51 pm 
Online
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 482
Pursuant to my last comment regarding the gdt_flush you could use something like:
Code:
gdt_flush:
    lgdt [gdt_ptr]        ; Load the new GDT pointer
    mov ax, 0x10          ; Data selector
    mov ss, ax
    mov es, ax
    mov ds, ax
    mov fs, ax
    mov gs, ax
    push 0x08             ; Code selector
    push .farjmp
    o64 retf               ; Perform an indirect 16:64 JMP using retf to jump to .farjmp label
.farjmp:
    ret


Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 3:02 pm 
Offline

Joined: Sun Jun 02, 2019 5:05 am
Posts: 7
Thanks for getting times to help me :)

I normally opened access to my gitlab : https://gitlab.com/epsilon99/os_tybe_uefi.git

I tried your code but it crash at the retf instruction.
I thought i did not had to perform this kind of far jump as EFI already put the 64 bit mode in place, that's why i only put lgdt in my gdt flush


Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 3:02 pm 
Online
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 482
I bungled the code and had to edit it after as I didn't have the proper o64 retf for the 16:64 return initially. You probably saw my code before the edit. Sorry.

When it comes to the code segment (CS) when your interrupt handlers fire it will attempt to reload CS when the iretq is done. At that point it will check the access rights for CS and will fail if CS's selector doesn't point to a proper code descriptor. If CS happens to be something that isn't a valid CS selector it should fault.


Last edited by MichaelPetch on Sat Aug 03, 2019 3:17 pm, edited 2 times in total.

Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 3:10 pm 
Offline

Joined: Sun Jun 02, 2019 5:05 am
Posts: 7
It works ! thank you very much !

Do you think i have to save the segment and restore them in my asm interrupt handler or the current code is enough (at least for the moment)?

Trying to solve this problem i read a bunch of other project and saw some common part in their int handler. Could you help understand them :
- some project perform a swapgs instruction
- some others the cld instruction

In any case thank you very much, i've been stuck on this for weeks :D


Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 3:37 pm 
Online
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 482
The current code is fine for the moment. You don't need to save and restore the other segment registers unless your OS is running threads/processes in Long mode's 32-bit (or 16-bit) compatibility mode. If you are doing that then you will need to save and restore those segments because in those modes segmentation still matters. You may wish to save them on the stack if you want an exception handler to be able to determine what the previous values were for debug purposes (they become accessible as part of your *registers* struct that is passed to the irq/isr handlers)

You will likely need to start using swapgs when your OS starts using more than one CPU. Each CPU may wish to have its own kernel data area in memory and usually that is where GS comes in handy (each CPU can have a different base set in GS). You'd then generally have a swapgs at the beginning and end of your interrupt handler.

As for CLD it should always appear in your interrupt handler before calling a function written for C (or any interurpt handler that potentially uses string instructions). C calling convention (per the AMD64 System V ABI) expects that the direction flag (DF) is clear (0). CLD clears the direction flag which means all the string instructions (lods, stos, scas etc) have forward movement. If some code had used STD (set the DF bit) and was interrupted the interrupt handler would be running with the wrong direction flag and if the interrupt handler code used string instructions it won't work as expected. Many interrupt handlers don't do a CLD and those ones are generally buggy.


Last edited by MichaelPetch on Sat Aug 03, 2019 3:58 pm, edited 3 times in total.

Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 3:50 pm 
Offline

Joined: Sun Jun 02, 2019 5:05 am
Posts: 7
Thank you for these information, it helps me a lot :)

For the moment i'll keep my interrupt handler like this (just added the CLD ;) ) until i work on threads (it's on the todo list).
I'm gonna jump to memory management now and port my old 32 bit memory manager to 64 bit.

Osdev wiki and forum is really the best place to find information and help on hobby os dev. I would never have advanced without it ^^


Top
 Profile  
 
 Post subject: Re: UEFI x64 interrupt help
PostPosted: Sat Aug 03, 2019 4:08 pm 
Online
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 482
No problem. Your are welcome. I should point out I simplified the idea of swapgs being used (when you start using it) at the beginning of an interrupt and at the end. Swapgs should only be done if the processor wasn't in ring 0 at the time the interrupt/exception occurred. Swapgs isn't nestable so you have to check the current ring. You can determine the ring that was interrupted by looking at the bottom 2 bits of the CS selector that was pushed on the stack by the CPU when the interrupt occurred (RFlags, and CS:RIP are all pushed automatically by the CPU on an exception/interrupt)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 15 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot], MichaelPetch and 9 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group