%macro ISR_NOERRCODE 1  ; define a macro, taking one parameter
  ;[GLOBAL isr%1]        ; %1 accesses the first parameter.
  isr%1:
    cli
    push byte 0
    push byte %1
    jmp isr_common_stub
%endmacro


%macro ISR_ERRCODE 1
  ;[GLOBAL isr%1]
  isr%1:
    cli
    push byte %1
    jmp isr_common_stub
%endmacro

%macro SETUP_ISR_X 1
        mov eax,isr%1    ;base isr
        mov [idt_temp], word ax         ;lower 16 bits
        mov [idt_temp+2],word 0x08      ;kernel segment selector
        mov [idt_temp+4],byte 0x0       ;always 0   
        ; We must change 0x8E with 0xEE below when we get to using user-mode.
        ; It sets the interrupt gate's privilege level to 3.
        mov [idt_temp+5],byte 0x8E      ;0x8E | 0x60 = 0xEE... we have to enable this later on
        shld edx,eax,16
        mov [idt_temp+6],word dx
        ;store idt_temp in idt and repeat the process
        mov esi,idt_temp
        mov edi,idt+(%1*8)
        mov ecx,2
        rep movsd       ;verify this is working!!!!!!!!!! DO NOT LET IT AS IS WITHOUT CHECKING
%endmacro



SECTION .data
isr_notification: db 'Recieved Interrupt.',`\n`,0x0



;;this is our IDT entry
idt_ptr_struct:
        dw idt_end - idt - 1 ; size of the GDT
        dd idt ; linear address of GDT

;256 idt entries. each entry has 8 bytes. 256*8 =2048

SECTION .text
extern prints
        ;first we have to create the interrupt handlers

        ISR_NOERRCODE 0
        ISR_NOERRCODE 1
        ISR_NOERRCODE 2
        ISR_NOERRCODE 3
        ISR_NOERRCODE 4
        ISR_NOERRCODE 5
        ISR_NOERRCODE 6
        ISR_NOERRCODE 7
        ISR_ERRCODE   8
        ISR_NOERRCODE 9
        ISR_ERRCODE   10
        ISR_ERRCODE   11
        ISR_ERRCODE   12
        ISR_ERRCODE   13
        ISR_ERRCODE   14
        ISR_NOERRCODE 15
        ISR_NOERRCODE 16
        ISR_NOERRCODE 17
        ISR_NOERRCODE 18
        ISR_NOERRCODE 19
        ISR_NOERRCODE 20
        ISR_NOERRCODE 21
        ISR_NOERRCODE 22
        ISR_NOERRCODE 23
        ISR_NOERRCODE 24
        ISR_NOERRCODE 25
        ISR_NOERRCODE 26
        ISR_NOERRCODE 27
        ISR_NOERRCODE 28
        ISR_NOERRCODE 29
        ISR_NOERRCODE 30
        ISR_NOERRCODE 31



[GLOBAL init_idt]

init_idt:
   ;fill it with zero
	mov al,0x0
	mov ecx,2048
	mov edi,idt
	rep stosb
	;;BREAKPOINT: verify it's doing this as it should
	;xch bx,bx

	;set idt table:

	SETUP_ISR_X 0
	SETUP_ISR_X 1
	SETUP_ISR_X 2
	SETUP_ISR_X 3
	SETUP_ISR_X 4
	SETUP_ISR_X 5
	SETUP_ISR_X 6
	SETUP_ISR_X 7
	SETUP_ISR_X 8
	SETUP_ISR_X 9
	SETUP_ISR_X 10
	SETUP_ISR_X 11
	SETUP_ISR_X 12
	SETUP_ISR_X 13
	SETUP_ISR_X 14
	SETUP_ISR_X 15
	SETUP_ISR_X 16
	SETUP_ISR_X 17
	SETUP_ISR_X 18
	SETUP_ISR_X 19
	SETUP_ISR_X 21
	SETUP_ISR_X 22
	SETUP_ISR_X 23
	SETUP_ISR_X 24
	SETUP_ISR_X 25
	SETUP_ISR_X 26
	SETUP_ISR_X 27
	SETUP_ISR_X 28
	SETUP_ISR_X 29
	SETUP_ISR_X 30
	SETUP_ISR_X 31

	;load new idt
	call idt_flush
   
ret



idt_flush:
   lidt [idt_ptr_struct]        ; Load the IDT pointer.
   ret


;s is our common ISR stub. It saves the processor state, sets
; up for kernel mode segments, calls the C-level fault handler,
; and finally restores the stack frame.
isr_common_stub:
   pusha                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax

   mov ax, ds               ; Lower 16-bits of eax = ds.
   push eax                 ; save the data segment descriptor

   mov ax, 0x10  ; load the kernel data segment descriptor
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   call isr_handler

   pop eax        ; reload the original data segment descriptor
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   popa                     ; Pops edi,esi,ebp...
   add esp, 8     ; Cleans up the pushed error code and pushed ISR number
   sti
   iret           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP


isr_handler:
	mov esi,isr_notification
	call prints
ret


SECTION .bss

idt: resb 2048
idt_end:
idt_temp: resb 8
