UPDATE: This is solved. The initial long mode GDT had both size bit and long bit set to 1. The size bit has to be 0 for long mode to be valid.
I'm playing around with a x86_64 higher half kernel and trying to get interrupts working. The kernel enters long mode, installs an IDT successfully and busy waits. I registered an ISR for the keyboard but keep getting General Protection Fault when I press a key or manually generate an interrupt. The GPF was generated upon calling the ISR, not when returning from it.
I'm fairly new to x86_64 and am pretty confused on why segmentation still seems to have come into play.
Here's a consecutive snippet of QEMU log, generated using "-d int"
// This is the manual "int $1"
0: v=01 e=0000 i=1 cpl=0 IP=0008:ffffffff8010e730 pc=ffffffff8010e730 SP=0010:ffffffff8010bfb0 env->regs[R_EAX]=ffff801680000fff
RAX=ffff801680000fff RBX=0000000000000000 RCX=00000000001bfeb0 RDX=00000000ffff00a1
RSI=0000ffffffff8010 RDI=000000000000008b RBP=ffffffff8010bff0 RSP=ffffffff8010bfb0
R8 =0000000000000001 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=00000000001bfea0 R15=0000000000000008
RIP=ffffffff8010e730 RFL=00200246 [---Z-P-] CPL=0 II=1 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
CS =0008 0000000000000000 00000000 00609a00 DPL=0 CS64 [-R-]
SS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
DS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
FS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= ffffffff801001b0 00000017
IDT= ffffffff80168000 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000101000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0001ffffffff0021 CCD=0000ffffffff8010 CCO=CLR
EFER=0000000000000500
// First GPF
check_exception old: 0xffffffff new 0xd
1: v=0d e=0012 i=0 cpl=0 IP=0008:ffffffff8010e730 pc=ffffffff8010e730 SP=0010:ffffffff8010bfb0 env->regs[R_EAX]=ffff801680000fff
RAX=ffff801680000fff RBX=0000000000000000 RCX=00000000001bfeb0 RDX=00000000ffff00a1
RSI=0000ffffffff8010 RDI=000000000000008b RBP=ffffffff8010bff0 RSP=ffffffff8010bfb0
R8 =0000000000000001 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=00000000001bfea0 R15=0000000000000008
RIP=ffffffff8010e730 RFL=00200246 [---Z-P-] CPL=0 II=1 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
CS =0008 0000000000000000 00000000 00609a00 DPL=0 CS64 [-R-]
SS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
DS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
FS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= ffffffff801001b0 00000017
IDT= ffffffff80168000 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000101000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0001ffffffff0021 CCD=0000ffffffff8010 CCO=CLR
EFER=0000000000000500
// Second GPF
check_exception old: 0xd new 0xd
2: v=08 e=0000 i=0 cpl=0 IP=0008:ffffffff8010e730 pc=ffffffff8010e730 SP=0010:ffffffff8010bfb0 env->regs[R_EAX]=ffff801680000fff
RAX=ffff801680000fff RBX=0000000000000000 RCX=00000000001bfeb0 RDX=00000000ffff00a1
RSI=0000ffffffff8010 RDI=000000000000008b RBP=ffffffff8010bff0 RSP=ffffffff8010bfb0
R8 =0000000000000001 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=00000000001bfea0 R15=0000000000000008
RIP=ffffffff8010e730 RFL=00200246 [---Z-P-] CPL=0 II=1 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
CS =0008 0000000000000000 00000000 00609a00 DPL=0 CS64 [-R-]
SS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
DS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
FS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= ffffffff801001b0 00000017
IDT= ffffffff80168000 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000101000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0001ffffffff0021 CCD=0000ffffffff8010 CCO=CLR
EFER=0000000000000500
check_exception old: 0x8 new 0xd
// Triple faults and resets
Any help would be appreciated, thanks!
[SOLVED] GPF when calling ISR
[SOLVED] GPF when calling ISR
Last edited by Dominator on Sun Jun 29, 2014 4:36 pm, edited 1 time in total.
Re: GPF when calling ISR -trying to make sense out of a QEMU
1. use objdump to check what's on the fault address.
2. check the error code for the fault, it tell you what have went wrong.
2. check the error code for the fault, it tell you what have went wrong.
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: GPF when calling ISR -trying to make sense out of a QEMU
Well, the OP seems to have done just that...
Since this is actually a triple fault, there will have to be some error in the IDT/GDT/IST because the handler doesn't seem to allow itself to be invoked at all. If you try to use bochs, you will get a significantly more verbose log of what error happened exactly.
bluemoon wrote:1. use objdump to check what's on the fault address.
2. check the error code for the fault, it tell you what have went wrong.[/quote]int $1
---e=0012
It's a protection fault. That does not necessarily mean an error with segmentation, but also goes for all sorts of system structure errors and other generic problems.I'm fairly new to x86_64 and am pretty confused on why segmentation still seems to have come into play.
Since this is actually a triple fault, there will have to be some error in the IDT/GDT/IST because the handler doesn't seem to allow itself to be invoked at all. If you try to use bochs, you will get a significantly more verbose log of what error happened exactly.
Re: GPF when calling ISR -trying to make sense out of a QEMU
Hmm, that was too long that I missed it, but anyway, an error code of 0012 means problem with IDT entry 0010 (INT 1 handler).Combuster wrote:Well, the OP seems to have done just that...
The error code hints that the IDT may be setup incorrectly.installs an IDT successfully
Re: GPF when calling ISR -trying to make sense out of a QEMU
I would suggest using bochs to check if the idt structure is correct using the debugger (You would have to compile it yourself but its worth the time spent)
CookieOS. Want a cookie? Its only black and white for now though, probably as bad as my baking skills.
Re: GPF when calling ISR -trying to make sense out of a QEMU
Well, I compiled and installed bochs with x86_64 support, but it hangs in GRUB2.
The screen says "Booting kernel..." (GRUB2's message) while the last line of bochs log is
00018162983i[BIOS ] Booting from 07c0:0000
Seems like some infinite loop going on in GRUB2? QEMU is still booting it fine.
As for the IDT entry, I set it up with the address of the ISR handler, selector 0x08 and flags 0x8e. The flags correspond to:
P: 1
DPL: 00
S: 0
Type: 1110 (Interrupt gate)
I also believe the ISR handler (the function pointer) is valid since I can manually invoke it. Is there something wrong with the selector?
The screen says "Booting kernel..." (GRUB2's message) while the last line of bochs log is
00018162983i[BIOS ] Booting from 07c0:0000
Seems like some infinite loop going on in GRUB2? QEMU is still booting it fine.
As for the IDT entry, I set it up with the address of the ISR handler, selector 0x08 and flags 0x8e. The flags correspond to:
P: 1
DPL: 00
S: 0
Type: 1110 (Interrupt gate)
I also believe the ISR handler (the function pointer) is valid since I can manually invoke it. Is there something wrong with the selector?
Re: GPF when calling ISR -trying to make sense out of a QEMU
I had the same issue i think, it's not a bug in QEMU, if you are following bran's tutorial, when you do idt_flush and gdt_flush, as a parameter specify &gp and &idtp.
I have my kernel source on GitHub, and this is the commit that fixed that for me:
https://github.com/Enverbalalic/OSDev_K ... c3581918f0
I have my kernel source on GitHub, and this is the commit that fixed that for me:
https://github.com/Enverbalalic/OSDev_K ... c3581918f0
Re: GPF when calling ISR -trying to make sense out of a QEMU
Thanks, but I don't think that's the issue. I've dumped the IDT entry and it seems perfectly valid.kemoba wrote:I had the same issue i think, it's not a bug in QEMU, if you are following bran's tutorial, when you do idt_flush and gdt_flush, as a parameter specify &gp and &idtp.
I have my kernel source on GitHub, and this is the commit that fixed that for me:
https://github.com/Enverbalalic/OSDev_K ... c3581918f0
Here's the triple fault log from a keyboard interrupt:
6: v=21 e=0000 i=0 cpl=0 IP=0008:ffffffff8010e5e0 pc=ffffffff8010e5e0 SP=0010:ffffffff8010bfb0 env->regs[R_EAX]=00000000000000a0
RAX=00000000000000a0 RBX=0000000000000000 RCX=00000000001bfeb0 RDX=00000000001bff40
RSI=0000000000000018 RDI=ffffffff80168000 RBP=ffffffff8010bff0 RSP=ffffffff8010bfb0
R8 =0000000000000001 R9 =0000000000000000 R10=0000000000000000 R11=00000000ffffffff
R12=80108e000008e5f0 R13=0000000000000000 R14=0000000000000000 R15=ffffffff80168000
RIP=ffffffff8010e5e0 RFL=00200246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
CS =0008 0000000000000000 00000000 00609a00 DPL=0 CS64 [-R-]
SS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
DS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
FS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= ffffffff801001b0 00000017
IDT= ffffffff80168000 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000101000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000044 CCD=0000000000000000 CCO=EFLAGS
EFER=0000000000000500
check_exception old: 0xffffffff new 0xd
7: v=0d e=0008 i=0 cpl=0 IP=0008:ffffffff8010e5e0 pc=ffffffff8010e5e0 SP=0010:ffffffff8010bfb0 env->regs[R_EAX]=00000000000000a0
RAX=00000000000000a0 RBX=0000000000000000 RCX=00000000001bfeb0 RDX=00000000001bff40
RSI=0000000000000018 RDI=ffffffff80168000 RBP=ffffffff8010bff0 RSP=ffffffff8010bfb0
R8 =0000000000000001 R9 =0000000000000000 R10=0000000000000000 R11=00000000ffffffff
R12=80108e000008e5f0 R13=0000000000000000 R14=0000000000000000 R15=ffffffff80168000
RIP=ffffffff8010e5e0 RFL=00200246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
CS =0008 0000000000000000 00000000 00609a00 DPL=0 CS64 [-R-]
SS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
DS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
FS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= ffffffff801001b0 00000017
IDT= ffffffff80168000 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000101000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000044 CCD=0000000000000000 CCO=EFLAGS
EFER=0000000000000500
check_exception old: 0xd new 0xd
8: v=08 e=0000 i=0 cpl=0 IP=0008:ffffffff8010e5e0 pc=ffffffff8010e5e0 SP=0010:ffffffff8010bfb0 env->regs[R_EAX]=00000000000000a0
RAX=00000000000000a0 RBX=0000000000000000 RCX=00000000001bfeb0 RDX=00000000001bff40
RSI=0000000000000018 RDI=ffffffff80168000 RBP=ffffffff8010bff0 RSP=ffffffff8010bfb0
R8 =0000000000000001 R9 =0000000000000000 R10=0000000000000000 R11=00000000ffffffff
R12=80108e000008e5f0 R13=0000000000000000 R14=0000000000000000 R15=ffffffff80168000
RIP=ffffffff8010e5e0 RFL=00200246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
CS =0008 0000000000000000 00000000 00609a00 DPL=0 CS64 [-R-]
SS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
DS =0010 0000000000000000 00000000 00609300 DPL=0 DS [-WA]
FS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
GS =0018 0000000000000000 ffffffff 00cf9300 DPL=0 DS [-WA]
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= ffffffff801001b0 00000017
IDT= ffffffff80168000 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000101000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000044 CCD=0000000000000000 CCO=EFLAGS
EFER=0000000000000500
check_exception old: 0x8 new 0xd
I've dumped IDT[33] (keyboard interrupt) to R11 and R12, which reads 0x00000000ffffffff80108e000008e5f0
Parsing it, we get the address for the ISR handler as 0xffffffff8010e5f0, which is correct according to my objdump.
The selector is 0x08, which also seems right
The flag is 0x8e, which is also correct.
Once again the ISR wasn't invoked at all, as the GPF was triggered upon calling it. The value for PC corresponds to essentially a "jmp $1" I put at the end of the kernel's main function.
Also, do I need to fiddle with GDT in long mode? I also tried that before loading IDT, but again got GPF when I tried moving "0x08" into ss (stack selector). I checked the GDT entry and it also seemed perfectly valid.
Pretty confused now...
Re: GPF when calling ISR -trying to make sense out of a QEMU
Problem solved. The initial GDT was setup wrong, both the size bit and the long bit were 1. The size bit has to be 0 in long mode.
I didn't write that part of the code so I assumed it was correct , although I don't know why no GPF was triggered earlier (before the interrupt).
I didn't write that part of the code so I assumed it was correct , although I don't know why no GPF was triggered earlier (before the interrupt).