Page 3 of 4

Re: IDT Help

Posted: Thu Mar 11, 2021 11:22 pm
by isaiah0311
SKC wrote: Well yes, but actually no. The loop sets the entries to the same handler. If you use it for the entire IDT, every interrupt/exception/IRQ will call the same code. Since you're in a very early stage, you can set the exception entries (0-31) to the same handler. However, as I said before, you will need to give each interrupt its own handler at some point. But for now, setting all the exceptions (only exceptions, not IRQs) to a dummy handler that just hangs is fine.
Alright, I think I'm starting to understand it more. So basically in the IDT label I need to define 32 exceptions, 16 IRQs, and then the pointer? The loop has a counter of 48, so it sets all 32 exceptions and 16 IRQs to the same handler. But only the exceptions can have the same handler (for now, later that has to be changed)? So I should change the counter to 32, and then add code to set each of the 16 IRQs to a different handler? What should that handlers for the IRQs do? Also, should I call the loop after I load the IDT or before?

Re: IDT Help

Posted: Fri Mar 12, 2021 12:20 am
by SKC
isaiah0311 wrote:Alright, I think I'm starting to understand it more. So basically in the IDT label I need to define 32 exceptions, 16 IRQs, and then the pointer? The loop has a counter of 48, so it sets all 32 exceptions and 16 IRQs to the same handler. But only the exceptions can have the same handler (for now, later that has to be changed)? So I should change the counter to 32, and then add code to set each of the 16 IRQs to a different handler?
Exactly.
isaiah0311 wrote:What should that handlers for the IRQs do?
The only thing that is common among IRQ handlers is that they send EOI (End Of Interrupt, you can read more about it here). Besides that, each IRQ handler is built to communicate with different hardware. Since you started this topic saying that you want to get keyboard input, I'll use it as an example. The keyboard uses IRQ1 (interrupt 33), and the handler would probably read from the keyboard and save the input somewhere. You can set the IRQs you don't use/support to a dummy handler that sends EOI and returns.
isaiah0311 wrote:Also, should I call the loop after I load the IDT or before?
Before. Loading an empty/corrupt IDT is like not having an IDT.

Re: IDT Help

Posted: Fri Mar 12, 2021 10:36 am
by isaiah0311
So here is the current main64.asm file. I'm still getting issues when I enable interrupts. If I don't enable interrupts it freezes before loading the kernel which is a new issue.

Code: Select all

global long_mode_start
extern gdt.data
extern kernel_main

section .text
bits 64
long_mode_start:
	mov ax, gdt.data
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax

	call map_entries
	lidt [idt.pointer]
	sti
	
	call kernel_main
	mov rax, 60
	mov rdi, 2
	syscall

map_entries:
	mov rbx, idt
.map_exceptions:
	mov rdx, 0
	mov rax, exception_handler
	mov rcx, 32
	jmp .loop
.map_irqs_pic1:
	mov rdx, 1
	mov rax, isr_handler.pic1
	mov rcx, 8
	jmp .loop
.map_irqs_pic2:
	mov rdx, 2
	mov rax, isr_handler.pic2
	mov rcx, 8
.loop:
	mov word [rbx], ax
	shr rax, 16
	mov word [rbx + 6], ax
	shr rax, 16
	mov dword [rbx + 8], eax
	add rbx, 16
	dec rcx
	jne .loop

	test rdx, 0
	je .map_irqs_pic1
	
	test rdx, 1
	je .map_irqs_pic2
	ret

idt:
.exception_0:
        dw 0
        dw 0x8
        db 0
        db 10001110b
        dw 0
        dd 0
        dd 0
; --------------------------------
; exception_1 - 30
; --------------------------------
.exception_31:
        dw 0
        dw 0x8
        db 0
        db 10001110b
        dw 0
        dd 0
        dd 0
.irq_0:
	dw 0
	dw 0x8
	db 0
	db 10001110b
	dw 0
	dd 0
	dd 0
; --------------------------------
; irq_1 - 14
; --------------------------------
.irq_15:
        dw 0
        dw 0x8
        db 0
        db 10001110b
        dw 0
        dd 0
        dd 0
.pointer:
        dw $ - idt - 1
        dq idt

exception_handler:
	jmp $

isr_handler:
.pic1:
	mov ax, 0x20
	out 0x20, ax
	iretq
.pic2:
	mov ax, 0x20
	out 0xa0, ax
	iretq

Re: IDT Help

Posted: Fri Mar 12, 2021 10:50 am
by SKC
What is gdt.data? Is it a selector, or is it the data descriptor in your GDT?

Re: IDT Help

Posted: Fri Mar 12, 2021 11:01 am
by isaiah0311
SKC wrote:What is gdt.data? Is it a selector, or is it the data descriptor in your GDT?
It's the data descriptor. I used the example in the wiki.

Code: Select all

section .rodata
gdt:
.null: equ $ - gdt
        dw 0xffff
        dw 0
        db 0
        db 0
        db 1
        db 0
.code: equ $ - gdt
        dw 0
        dw 0
        db 0
        db 10011010b
        db 10101111b
        db 0
.data: equ $ - gdt
        dw 0
        dw 0
        db 0
        db 10010010b
        db 00000000b
        db 0
.pointer:
        dw $ - gdt - 1
        dq gdt

Re: IDT Help

Posted: Fri Mar 12, 2021 11:24 am
by SKC
You need to set the data segment registers to the data selector, not descriptor.
Also, I don't think that your code descriptor is valid. I set the 7th byte (10101111b in your code) to 00100000b.

Re: IDT Help

Posted: Fri Mar 12, 2021 11:47 am
by isaiah0311
SKC wrote:You need to set the data segment registers to the data selector, not descriptor.
Also, I don't think that your code descriptor is valid. I set the 7th byte (10101111b in your code) to 00100000b.
I changed the byte to 00100000b and the data segment registers to 0x10 again. The OS still didn't boot.
I checked the wiki. The comment next to 10101111b is: granularity, 64 bits flag, limit19:16.
It also labels the .data as the descriptor and then loads gdt.data into the segment registers.
Is it valid both ways, or is the wiki wrong?
Here is the link.

Re: IDT Help

Posted: Fri Mar 12, 2021 11:59 am
by SKC
isaiah0311 wrote:The comment next to 10101111b is: granularity, 64 bits flag, limit19:16.
AMD's manual says that granularity and limit are ignored, so I guess it's fine. Also, I didn't notice that, but I think 'equ $ - gdt' sets the labels to the selectors (so you can do 'mov ax,gdt.data'). Anyway, I think it's clearer to use the selector itself.
isaiah0311 wrote:The OS still didn't boot.
What happens? Exception? Triple fault? It just hangs?

Re: IDT Help

Posted: Fri Mar 12, 2021 12:11 pm
by isaiah0311
SKC wrote: What happens? Exception? Triple fault? It just hangs?
It just hangs.

Re: IDT Help

Posted: Fri Mar 12, 2021 1:08 pm
by isaiah0311
Update: It works... sort of?

The issue was in the loop where I map the IDT entries to the handler functions.
The new loop is this:

Code: Select all

map_entries:
   mov rbx, idt
.map_exceptions:
   mov rdx, 0
   mov rax, exception_handler
   mov rcx, 32
   jmp .loop
.map_irqs_pic1:
   mov rdx, 1
   mov rax, isr_handler.pic1
   mov rcx, 8
   jmp .loop
.map_irqs_pic2:
   mov rdx, 2
   mov rax, isr_handler.pic2
   mov rcx, 8
.loop:
   mov word [rbx], ax
   shr rax, 16
   mov word [rbx + 6], ax
   shr rax, 16
   mov dword [rbx + 8], eax
   add rbx, 16
   dec rcx
   jne .loop

   test rdx, rdx
   je .map_irqs_pic1
   
   dec rdx
   test rdx, rdx
   je .map_irqs_pic2
   ret
It now boots into the OS even with interrupts enabled. The issue I have now is when I press a key, it reboots.
Here is how the IRQs are handled:

Code: Select all

isr_handler:
.pic1
   mov ax, 0x20
   out 0x20, ax
   iretq
.pic2
   mov ax, 0x20
   out 0xa0, ax
   iretq
I know this won't read the keyboard input, but I didn't except it to cause a reboot. I figured it would just do nothing.

Re: IDT Help

Posted: Fri Mar 12, 2021 9:12 pm
by SKC
Wow. You know what I've just noticed? rax is not being set up properly after each loop iteration! I just shoved the code into a loop, and I overlooked that… To fix it, you need to use another register, and set rax to that register at the start of the loop. I'm thinking about something like:

Code: Select all

.loop:
   mov rax, r8 ; r8 is the additional register
   mov word [rbx], ax
   shr rax, 16
   mov word [rbx + 6], ax
   shr rax, 16
   mov dword [rbx + 8], eax
   add rbx, 16
   dec rcx
   jne .loop
And then in the rest of your map_entries function, just change rax to r8.

Re: IDT Help

Posted: Fri Mar 12, 2021 9:23 pm
by isaiah0311
SKC wrote:Wow. You know what I've just noticed? rax is not being set up properly after each loop iteration! I just shoved the code into a loop, and I overlooked that… To fix it, you need to use another register, and set rax to that register at the start of the loop. I'm thinking about something like:

Code: Select all

.loop:
   mov rax, r8 ; r8 is the additional register
   mov word [rbx], ax
   shr rax, 16
   mov word [rbx + 6], ax
   shr rax, 16
   mov dword [rbx + 8], eax
   add rbx, 16
   dec rcx
   jne .loop
And then in the rest of your map_entries function, just change rax to r8.
It works! Interrupts are enabled and it doesn't crash, even when I press a key.
So now the next step would be to assign the keyboard IRQ a handler of its own?

Re: IDT Help

Posted: Fri Mar 12, 2021 9:26 pm
by SKC
I'm glad it works! And yes, now you need to give the keyboard its own handler.

Re: IDT Help

Posted: Fri Mar 12, 2021 9:44 pm
by isaiah0311
SKC wrote:And yes, now you need to give the keyboard its own handler.
So how do I go about accessing the data for which key is pressed? After that can I just store it in RAX and then call a C function?

Re: IDT Help

Posted: Fri Mar 12, 2021 10:00 pm
by SKC
isaiah0311 wrote:So how do I go about accessing the data for which key is pressed?
Read this.
isaiah0311 wrote:After that can I just store it in RAX and then call a C function?
And this.