; interrupt.s
bits 16
%pragma once

; mkidt :: void -> bool             ; make idt
mkidt:
    enter 8,0
    %assign stack   8
    %define PhyHi   bp-2
    %define PhyLo   bp-4
    %define Idtr_   bp-6
    %define Idt     bp-8
    pusha

    ; lea bx,ss:[PhyLo]
    ; pf "DEBUG: phylo=0x%x ",bx
    ; lea bx,ss:[PhyHi]
    ; pfln "phyhi=0x%x ",bx
    pf "  allocating phy memory... "
    ; dx:ax =
        palloc(1)
    jc .errphy

    push ax
    mov word ss:[PhyLo],ax
    xor dh,dh
    mov word ss:[PhyHi],dx
    pf "addr=%x:",dx
    pop bx
    pfln "0x%x",bx

    pf "  allocating vir memory... "
    ; ax =
        valloc(ss:[PhyHi], ss:[PhyLo], (P|Ring0|S|W), 7)
    jc .errvir
    push ax
    mov bx,ax
    pf "idtr_sel=0x%x ",bx
    
    mov word bx,ss:[PhyLo]
    add bx,8               ; bx=offset of idt (offset from idtr)
    ; ax =
        valloc(ss:[PhyHi], bx, (P|Ring0|S|W), ((IdtSz*8)-1))
    jc .errvir

    mov bx,ax               ; bx=idt seg
    push bx
    pfln "idt_sel=0x%x",bx
    pop bx
    pop ax                  ; ax=idtr seg
    mov word ss:[Idtr_],ax
    mov word ss:[Idt],bx
    
    chseg(ds,csselector)
        mov word ax,ss:[Idt]
        xor bx,bx
        mov word ds:[bx+confseg.idtseg],ax
    sret(ds)

    chseg(ds,ss:[Idtr_])
        xor bx,bx                ; bx=idtr addr
        mov si,0x0008            ; si=idt offset from idtr
        add word si,ss:[PhyLo]   ; si=low word of phy addr of idt
        mov word ds:[bx+Idtr(low)],si

        mov word ax,ss:[PhyHi]   ; al=high byte of the above
        and ax,0xff
        mov byte ds:[bx+Idtr(hi)],al
        mov word ds:[bx+Idtr(sz)],((IdtSz*8)-1)
        mov al,0xff
        mov byte ds:[bx+Idtr(res)],al
    sret(ds)

    pf "  zeroing the idt memspace... "
    chseg(es,ss:[Idt])
        xor bx,bx           ; bx=dest addr
                            ; bl=character (\0)
        mov cx,(IdtSz*8)    ; cx=size
        set(bx, bx, cx)
    sret(es)
    pfln "%d chars written",cx

    mov word ax,ss:[Idt]    ; ax=idt seg
    push ax
    call initidt
    jc .erridt
    add sp,2
    ; ctxidt

    showgdt()
    mov word bx,ss:[Idt]
    showidt(bx)
    ; pf "  flushing idt... "
    ; lidt [ss:Idtr_]
    ; pfln "ok"
    pf "  activating the idt... "
    chseg(ds,[Idtr_])
        xor bx,bx
        lidt ds:[bx]
    sret(ds)
    pfln "ok"

    sti
    ; mov bx,0
    ; mov ax,7
    ; div bx

    pfln "Still kicking!"
    ; show(0x0038,0x0000)
    ; show(0x0038,0x0008)
    ; show(0x0038,0x0010)
    ; show(0x0038,0x0018)

    %undef Idt
    %undef Idtr_
    %undef PhyLo
    %undef PhyHi
    jmp .end

 .errphy:
    mov ax,0x0001
    push ax
    jmp .err
 .errvir:
    mov ax,0x0002
    push ax
    jmp .err
 .erridt:
    pop ax
    mov ax,0x0003
    push ax
    jmp .err
 .err:
    mov bx,ax
    pfln "err=%d",bx
    pop ax
    popa
    add sp,stack
    stc
    leave
    ret

 .end:
    xor ax,ax
    popa
    add sp,stack
    %undef stack

    clc
    leave
    ret

mkisr 0,1,2,3,4,5,6,7
    isr8:
        times 4 nop
        iret
        xor ah,ah
        mov byte al,8
        push ax
        jmp isrstub

        %assign alignment   ($-isr8)
        %assign padding     (16-alignment)
         .pad:
            times padding nop
        %undef padding
        %undef alignment
mkisr 9
    isr10:
        times 4 nop
        xor ah,ah
        mov byte al,10
        push ax
        jmp isrstub

        %assign alignment   ($-isr10)
        %assign padding     (16-alignment)
         .pad:
            times padding nop
        %undef padding
        %undef alignment
    isr11:
        times 4 nop
        xor ah,ah
        mov byte al,11
        push ax
        jmp isrstub

        %assign alignment   ($-isr11)
        %assign padding     (16-alignment)
         .pad:
            times padding nop
        %undef padding
        %undef alignment
    isr12:
        times 4 nop
        xor ah,ah
        mov byte al,12
        push ax
        jmp isrstub

        %assign alignment   ($-isr12)
        %assign padding     (16-alignment)
         .pad:
            times padding nop
        %undef padding
        %undef alignment
    isr13:
        times 4 nop
        iret
        xor ah,ah
        mov byte al,13
        push ax
        jmp isrstub

        %assign alignment   ($-isr13)
        %assign padding     (16-alignment)
         .pad:
            times padding nop
        %undef padding
        %undef alignment
 
; parameter olympics 2026
mkisr   14,15,16,17,18,19,20,21,22,23,24,25,26, \
        27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46, \
        47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67, \
        68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88, \
        89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106, \
        107,108,109,110,111,112,113,114,115,116,117,118,119,120,121, \
        122,123,124,125,126,127,128,129,130,131,132,133,134,135,136, \
        137,138,139,140,141,142,143,144,145,146,147,148,149,150,151, \
        152,153,154,155,156,157,158,159,160,161,162,163,164,165,166, \
        167,168,169,170,171,172,173,174,175,176,177,178,179,180,181, \
        182,183,184,185,186,187,188,189,190,191,192,193,194,195,196, \
        197,198,199,200,201,202,203,204,205,206,207,208,209,210,211, \
        212,213,214,215,216,217,218,219,220,221,222,223,224,225,226, \
        227,228,229,230,231,232,233,234,235,236,237,238,239,240,241, \
        242,243,244,245,246,247,248,249,250,251,252,253,254,255

; isrstub :: int32 *seg:retaddr
;   -> int16 flags -> int8 errcode -> int8 interrupt -> void
isrstub:
    enter 0,0
    pusha

    mov cx,[bp+2]           ; cx=int vector
    and cx,0xff
    mov bx,[bp+4]           ; bx=err code
    mov ax,[bp+8]           ; ax=flags
    pf "[int %d] code=",cx
    pfln "0x%x",bx
    cmp byte cl,14
    jge .end

 .halt:
    cli
    hlt
    jmp .halt

 .end:
    popa
    leave
    add sp,4
    iret

; __showidt :: int16 idtseg? -> void
__showidt:
    enter 0,0
    push bx
    push cx
    push di

    mov bx,[bp+4]       ; bx=idt seg
    mov cx,IdtSz        ; cx=count
    xor di,di           ; di=offset

    push bx
    pf "will try 0x%x:",bx
    pop bx
    push di
    pfln "0x%x",di
    pop di
    pfln "Interrupt Descriptor Table:"
 .loop:
    ; show(bx,di)
    show(0x0038,di)
    add di,8
    loop .loop

 .end:
    pop di
    pop cx
    pop bx
    xor ax,ax
    clc
    leave
    ret

; initidt :: int16 seg -> bool
initidt:
    enter 0,0
    pusha

    mov bx,[bp+4]     ; bx=idt seg
    ; mov cx,IdtSz      ; cx=count
    xor cx,cx
    ; mov di,((IdtSz-1)*8)
    xor di,di
                      ; di=dest offset
    ; mov dl,0          ; dl=wordcount (0 is for testing)
    mov dl,cl          ; dl=wordcount (0 is for testing)
    mov dh, \
     (P|Ring0|IntGate)
                      ; dh=access byte for intgate

    pfln "adding idt entries"
 .loop:
    cmp cx,IdtSz
    jg .end
    ; ax=
        multiply(cx,16)
    xor si,si
    lea si,cs:[isr0]
    ; xor ax,ax
    ; mov al,dl
        xor dl,dl
    ; times 16 add word si,ax ; si=isr addr
    add si,ax ; si=isr addr
                       ; cs=code selector
    
    ; cf=
        setgate(bx,di,cs,si,dl,dh)
    jc .err
    add di,8
    jc .err
    pf "."
    inc cx
    inc dl
    jmp .loop

 .err:
    popa
    mov ax,0x0001
    stc
    leave
    ret

 .end:
    popa
    xor ax,ax
    clc
    leave
    ret

; struc Idt
;   .offset:  resw 1
;   .selector:resw 1 ; <<2
;   .wordcnt: resb 1
;   .xs:      resb 1
;   .res:     resw 1
; endstruc

; __show :: idtentry *seg:addr -> void
__show:
    enter 8,0
    %assign stack 8
    %define Offset      bp-7
    %define Sel         bp-4
    %define Words       bp-2
    %define Access      bp-1
    pusha

    mov dx,[bp+4]   ; dx=seg
    mov di,[bp+6]   ; di=idx

        ; mov dx,0x0038
    ; pf "show(0x%x",dx
    ; pfln ", 0x%x",di

    ; push dx
    ; pf "trying 0x%x:",dx
    ; pop dx
    ; push di
    ; pfln "0x%x",di
    ; pop di

    chseg(ds,dx)
        mov word ax,ds:[di+Idt.offset]
        mov word ss:[Offset],ax
            mov bx,ax
            pfln "     OFF=0x%x",bx
        mov word ax,ds:[di+Idt.selector]
        mov word ss:[Sel],ax
        xor ah,ah
        mov byte al,ds:[di+Idt.wordcnt]
        mov byte ss:[Words],al
        mov byte al,ds:[di+Idt.xs]
        mov byte ss:[Access],al
    sret(ds)

    ; ax=
        divide(di,8)
    mov si,ax
    mov word cx,ss:[Sel]
    mov byte dl,ss:[Words]
    mov byte dh,ss:[Access]
    
    pf "  [%d] ",si
    pf "addr=0x%x:",cx
    
    mov word bx,ss:[Offset]
    pf "0x%x ",bx
    xor bh,bh
    mov bl,dl
    pf "wc=%d ",bx
    mov bl,dh
    pfln "xs=0x%x",bx

 .end:
    popa
    xor ax,ax
    add sp,stack

    %undef stack
    %undef Access
    %undef Words
    %undef Sel
    %undef Offset

    clc
    leave
    ret

%if 0
; mkleaf :: int8 group -> int8 vector
;   -> isr *seg:addr -> struc *IntLeaf
mkleaf:
    %assign stack   10

    enter stack,0
    %define Ring        bp-2
    %define Segm        bp-4
    %define Idx         bp-6
    %define RootSeg     bp-8
    %define RootAddr    bp-10
    pusha

    mov cx,[bp+4]       ; cl=group
    mov ax,[bp+6]
    mov ch,al           ; ch=int no
    mov dx,[bp+8]       ; dx=handler seg
    mov di,[bp+10]      ; di=handler addr

    ; ax=
        getring()
    mov word ss:[Ring],ax
    ; ax=
        getconf(inttreeseg0)
    jc .errconf
    mov bx,ax       ; bx=seg for ring0
    mov word ss:[RootSeg],bx
    cmp word ss:[Ring],0
    je .r0
 .r1:
    ; ax=
        getconf(inttreeseg1)
    jc .errconf
    mov bx,ax          ; bx=seg for ring1
 .r0:
    mov word ss:[Segm],bx
    
    ; ax=
        findslot(bx,0,MaxTrees)
    jc .errfull
    mov si,ax           ; si=idx of empty slot
    mov word ss:[Idx],si
    ; ax=
        multiply(si,IntTreeSz)
    mov si,ax           ; si=offset in bytes
    ; ax=
        getconf(inttreeroot)
    jc .errconf
    mov bx,ax             ; bx=addr (in r0-seg) for root
    mov word ss:[RootAddr],bx
    chseg(es,ss:[Segm])
        set(si,0,IntTreeSz)
        jc .errperm

        ; flags(only zero|group), int vector
        ;   i wait with P flag until the very last min
        mov byte es:[si+IntLeaf.flags],cl
        mov byte es:[si+IntLeaf.int],ch
        
        ; interrupt handler
        xor bx,bx
        mov bx,IntLeaf.handler
        mov word es:[bx+si+0],di    ; +0 is offset
        mov word es:[bx+si+2],dx    ; +2 is seg

        ; reserved part (must be 0)
        mov bx,si
        add bx,IntLeaf.reserved               ; bx=off
        mov dx,(IntLeaf.end-IntLeaf.reserved) ; dx=sz
        set(bx,0,dx)
        jnc .connect
 .errperm:
    sret(es)
    popa
    mov ax,0x0001
    jmp .err
 .errfull:
    popa
    mov ax,0x0002
    jmp .err
 .errconf:
    popa
    mov ax,0x0003
 .err:
    xor dx,dx
    add sp,stack
    stc
    leave
    ret

 .connect:
;     ; overcomplicated solutions
;     ; i think i'll start over (just this section thou)
;     ;

;     mov word di,ss:[RootAddr]
;     chseg(es,ss:[RootSeg])
;         ; 3 links, one for each group
;         xor dx,dx
;         test cl,Exceptions
;         jz .findfault
;         test cl,IRQs
;         jz .findirq
;         test cl,Traps
;         jz .findtrap
;      .findother:
;         or dl,Other
;         jmp .stub
;      .findtrap:
;         or dl,Traps
;         jmp .stub
;      .findirq:
;         or dl,IRQs
;         jmp .stub
;      .findfault:
;         or dl,Exceptions
;      .stub:
;             ; scanchild(struct es:rootidx,
;             ;     prefix IntNode/IntLeaf,
;             ;     suffix fieldparent,
;             ;     suffix fieldchild)
;      .s1:
;         ; ax=
;             scanchild(di,IntNode,south1,flags)
;         jc .s2
;         test al,dl
;         jz .s1ftw
;      .s2:
;         ; ax=
;             scanchild(di,IntNode,south2,flags)
;         jc .s3
;         test al,dl
;         jz .s2ftw
;      .s3:
;         ; ax=
;             scanchild(di,IntNode,south3,flags)
;         jc .errperm
;         test al,dl
;         jz .s3ftw
;         jmp .errperm

;      .s1ftw:
;         mov bx,IntNode.south1
;         jmp .common
;      .s2ftw:
;         mov bx,IntNode.south2
;         jmp .common
;      .s3ftw:
;         mov bx,IntNode.south3

;      .common:
;         ; we can reuse the old stuff
;         mov word ax,es:[bx+di+0]  ; ax=offset
;         mov word ss:[RootAddr],ax ; actually the L2 and
;                                   ;     not the root
;         mov word ax,es:[bx+di+2]  ; ax=seg
;         mov word ss:[RootSeg],ax
    
;         ; next we need to check if the L2 node
;         ;   is connected anywhere downstream

 .present:
    or cl,Pbit
    chseg(es,ss:[Segm])
        mov byte es:[si+IntLeaf.flags],cl
    sret(es)

 .end:
    popa
    mov word dx,ss:[Segm]
    mov ax,si
    add sp,stack

    %undef RootAddr
    %undef RootSeg
    %undef Idx
    %undef Segm
    %undef Ring
    %undef stack

    clc
    leave
    ret
%endif


