Page 2 of 4

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 2:49 pm
by austanss
Octocontrabass wrote: Exception handlers are more important, and yours are very broken.
You couldn't have said it better. I had a keyboard handler written yet when I press the keyboard nothing happens... but when I manually int 0x21 it works for some reason? It faults though because it's reading from port 0x60 when there is no data...

Also, my exception handlers are very broken... the registers aren't handed to the function. This happened I assume because of the switch in calling convention from i386 to x86-64. All my code was designed around the calling conventions of i386, and I didn't think about fixing that when I ported it.

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 3:22 pm
by austanss
So I fixed the calling conventions and now the interrupts are spamming. My hypothesis is that invalid memory is being accessed and the CPU is throwing an exception, but then the invalid memory is accessed again and again until the CPU resets.

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 4:05 pm
by Octocontrabass
You can run QEMU with "-d int" to see which interrupt it is. If it's an exception, QEMU will also display the error code.

Don't forget to disable interrupts until your exception handlers are working.

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 6:53 pm
by austanss
So I fixed the ISRs, but I feel like I'm completely overlooking something with the IRQs.

When I trigger an IRQ, the IRQ handler is called, but afterwards I get a GP fault. I can't tell if this is a form of jump to garbage or invalid memory, however.

Although, looking at the register dump, I see some weird values.

RBP: 0x000000003FF07990
RSP: 0x000000000010EF88

That's a big stack...

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 7:48 pm
by Octocontrabass
rizxt wrote:So I fixed the ISRs,
I wouldn't call this fixed. You must pass either a pointer or a reference to the registers struct. Passing the registers struct by value allows the compiler to stomp all over it, which will cause some nasty bugs in the future.

You do not need to push RSP, the CPU already does it for you. You need to push R8, R9, R10, and R11 since any C++ code you call may overwrite them. You probably also want to push R12, R13, R14, and R15 so your exception handler can print them.

Your interrupt handlers should never start with CLI or end with STI. If you want to disable IRQs when an interrupt occurs, use an interrupt gate in your IDT. The CPU saves RFLAGS on the stack when the interrupt occurs and restores it with IRETQ so you don't need to explicitly re-enable IRQs.
rizxt wrote:but I feel like I'm completely overlooking something with the IRQs.
You're trying to restore something you didn't save. You didn't save several registers you're clobbering.

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 8:12 pm
by austanss
I'm trying to structure my register save correctly, so I must ask:

What registers does the CPU automatically push onto the interrupt stack, and in what order?

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 8:38 pm
by austanss
OK, after reading the handy AMD64 APM vol. 2, I figured it out:

The CPU pushes these registers onto the stack in this order

Code: Select all


|    RIP    |
| --------- |
|    CS     |
| --------- |
|  RFLAGS   |
| --------- |
|  SS:RSP   |

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 9:09 pm
by austanss
I fixed the ISRs yet can't figure out the IRQs. I removed the mov, ds, gs, fs... etc. lines, yet it still dudn't work, I'm going to try using the same parameters as ISR, although that is inefficient.

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 9:12 pm
by austanss
Aight that don't work.

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 9:13 pm
by Octocontrabass
Your struct is missing RSP.

Your IRQ handler clobbers RDI and RSI. It also pops too many things off the stack before IRETQ.

And I didn't notice it earlier, but you need CLD before you call any functions from within your interrupt handlers.

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 9:16 pm
by austanss

Code: Select all

; Common ISR code
isr_common_stub:
   ; Save CPU state into a structure,
   ; assembled onto the stack
   pusha 			; Pushes rdi, rsi, rbp and r[a-d]x
   mov ax, ds 		; Set the lower 16 bits of rax to ds
   push rax 		; save the value of rax, which is now ds
   mov ax, 0x10  	; kernel data segment descriptor
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   ; Since we assembled the struct
   ; on the stack, we can simply
   ; pass the stack pointer as a
   ; pointer to our structure
   mov rdi, rsp

  ; 2. Call C handler
   cld
   call ISRHandler

  ; 3. Restore state
   pop rbx
   mov ds, bx
   mov es, bx
   mov fs, bx
   mov gs, bx
   popa
   add rsp, 8 ; Cleans up the pushed error code and pushed ISR number
   iretq ; pops 5 things at once: CS, EIP, EFLAGS, SS, and RSP

; Common IRQ code. Identical to ISR code except for the 'call'
; and the 'pop ebx'
irq_common_stub:
   ; Save CPU state into a structure,
   ; assembled onto the stack
   pusha 			; Pushes rdi, rsi, rbp and r[a-d]x
   mov ax, ds 		; Set the lower 16 bits of rax to ds
   push rax 		; save the value of rax, which is now ds
   mov ax, 0x10  	; kernel data segment descriptor
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   ; Since we assembled the struct
   ; on the stack, we can simply
   ; pass the stack pointer as a
   ; pointer to our structure
   mov rdi, rsp

  ; 2. Call C handler
   cld
   call IRQHandler

  ; 3. Restore state
   pop rax
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax
   popa
   add rsp, 8 ; Cleans up the pushed error code and pushed ISR number
   iretq ; pops 5 things at once: CS, EIP, EFLAGS, SS, and RSP
Haven't pushed this code yet because I don't feel comfortable committing it yet. I added CLD and it still don't work. I also changed the C IRQHandler to use the Registers structure reference parameter...

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 9:23 pm
by Octocontrabass
I don't see anything immediately wrong with that code. What exactly do you mean when you say it doesn't work?

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 9:30 pm
by austanss
I get a GP fault, error code 48.

Serial output from the IRQ handler:

Code: Select all

IRQ TRIGGERED


FATAL ERROR: CPU EXCEPTION 0x000000000000000D -/- ERROR CODE 0x0000000000000030
DS: 0x0000000000000010
RDI: 0x0000000000000020 | RSI: 0x0000000000000020 | RBP: 0x000000003FF07990 | RSP: 0x000000000010EF90
RBX: 0x0000000000000000 | RDX: 0x0000000000000020 | RCX: 0x000000000000001D | RAX: 0x0000000000000030
RIP: 0x0000000000100A27 | CS: 0x0000000000000008
RFLAGS: 0x0000000000000012
It definitely arises after the C++ handler is called, because the IRQ TRIGGERED message is sent from inside the C++ handler.

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 9:43 pm
by Octocontrabass
rizxt wrote:

Code: Select all

  ; 3. Restore state
   pop rax
   mov ds, ax

Code: Select all

ERROR CODE 0x0000000000000030
RAX: 0x0000000000000030
Is RIP pointing to this MOV instruction? Could it be faulting because the segment selector that was saved earlier is invalid? Did you load valid segment selectors after setting up the GDT?

Re: converting 32-bit IDT to 64-bit IDT

Posted: Tue Dec 01, 2020 9:48 pm
by austanss
Usually when I read the RIP value, it points to null bytes.

And it still does now.