Project: OSMain
asm {
USE64
IRQ_VECTORS::
//IDTInit() uses this table
//for the initial vectors.
//Other handlers are set, later,
//with SetIDTEntry().
//See SetIDTEntry Grep
        DU4 IRQ00,IRQ01,IRQ02,IRQ03;
        DU4 IRQ04,IRQ05,IRQ06,IRQ07;
        DU4 IRQ08,IRQ09,IRQ0A,IRQ0B;
        DU4 IRQ0C,IRQ0D,IRQ0E,IRQ0F;

        DU4 IRQ10,IRQ11,IRQ12,IRQ13;
        DU4 IRQ14,IRQ15,IRQ16,IRQ17;
        DU4 IRQ18,IRQ19,IRQ1A,IRQ1B;
        DU4 IRQ1C,IRQ1D,IRQ1E,IRQ1F;

        DU4 IRQ20,IRQ21,IRQ22,IRQ23;
        DU4 IRQ24,IRQ25,IRQ26,IRQ27;
        DU4 IRQ28,IRQ29,IRQ2A,IRQ2B;
        DU4 IRQ2C,IRQ2D,IRQ2E,IRQ2F;

        DU4 IRQ30,IRQ31,IRQ32,IRQ33;
        DU4 IRQ34;

//Set MAX_INITIAL_IDT if you add more

// ************************************
COUT_PUT_F8:
        PUSH_C_REGS
        PUSH    U8 8[RBP]
        CALL    _PUT_FLOAT
        ADD     RSP,8
        POP_C_REGS
COUT_RETURN:
        RET
COUT_PUT_STR:
        PUSH    RSI
        MOV     RSI,RAX
        CALL    PUT_STR
        POP     RSI
        RET

COUT_JMP_TABLE:
        DU8     PUT_HEX_U4;
        DU8     PUT_HEX_U4;
        DU8     PUT_HEX_U1;
        DU8     PUT_HEX_U1;
        DU8     PUT_HEX_U2;
        DU8     PUT_HEX_U2;
        DU8     PUT_HEX_U4;
        DU8     PUT_HEX_U4;
        DU8     PUT_HEX_U8;
        DU8     PUT_HEX_U8;
        DU8     COUT_PUT_F8;
        DU8     COUT_PUT_F8;

//ptr types
        DU8     PUT_HEX_U4;
        DU8     PUT_HEX_U4;
        DU8     COUT_PUT_STR;
        DU8     COUT_PUT_STR;

COUT_JOIN::
        OR      RBX,RBX
        JZ      @@100
@@20:   MOV     RDX,U8 [RBP]
        MOV     RAX,U8 8[RBP]
        CMP     RDX,IT_U1+IT_NUM_IT
        JBE     @@21
        MOV     RDX,IT_U8
@@21:   CALL    U8 COUT_JMP_TABLE[RDX*8]
        SUB     RBP,16
        DEC     RBX
        JNZ     @@20
@@100:  RET

IRQ30:  JMP     I4 _MP_CRASH

//I_COUT
//See PrsCout
IRQ31:: PUSH    RBP
        MOV     RBP,RSP
        BT      U8 24[RBP],RFLAGS_INTERRUPTS
        JNC     @@I31
        STI
@@I31:
        MOV     RBP,U8 32[RBP]
        MOV     RBX,RAX         //GET ARG CNT
        ADD     RBX,RBX
        LEA     RBP,-16[RBP+RBX*8]
        MOV     RBX,RAX         //GET ARG CNT
        CALL    COUT_JOIN
        POP     RBP
        IRET


//I_COUTLN
IRQ32:: PUSH    RBP
        MOV     RBP,RSP
        BT      U8 24[RBP],RFLAGS_INTERRUPTS
        JNC     @@I32
        STI
@@I32:
        MOV     RBP,U8 32[RBP]
        MOV     RBX,RAX         //GET ARG CNT
        ADD     RBX,RBX
        LEA     RBP,-16[RBP+RBX*8]
        MOV     RBX,RAX         //GET ARG CNT
        CALL    COUT_JOIN
        PUSH    RAX
        MOV     RAX,CH_CR
        CALL    PUT_CHAR
        MOV     RAX,CH_LINE_FEED
        CALL    PUT_CHAR
        POP     RAX
        POP     RBP
        IRET

//I_HIBERNATE
IRQ33:
        PUSH    RAX
        XOR     RAX,RAX
        MOV     EAX,U4 LAPIC_EOI
        MOV     U4 [RAX],0

        XOR     RAX,RAX
        LOCK
        BTS     U4 GS:CPU_CPU_FLAGS[RAX],CPUf_HIBERNATING

        STI
        HLT

        LOCK
        BTR     U4 GS:CPU_CPU_FLAGS[RAX],CPUf_HIBERNATING

        POP     RAX
        IRET

//I_WAKE
IRQ34:
        PUSH    RAX
        XOR     RAX,RAX
        MOV     EAX,U4 LAPIC_EOI
        MOV     U4 [RAX],0
        POP     RAX
        IRET

//I_TIMER
IRQ20:  CALL    SAVE_CONTEXT            //PREEMPTIVE
        CLD
        MOV     RBP,RSP
        MOV     RBX,U8 [RBP]
        MOV     U8 TASK_RIP[RSI],RBX
        MOV     RAX,U8 16[RBP]
        MOV     U8 TASK_RFLAGS[RSI],RAX
        MOV     RAX,U8 24[RBP]
        MOV     U8 TASK_RSP[RSI],RAX

        XOR     RAX,RAX
        MOV     RDI,U8 GS:CPU_ADDRESS[RAX]
        LOCK
        INC     U8 CPU_TOTAL_JIFFIES[RDI]

        BT      U8 TASK_TASK_FLAGS[RSI],TASKf_IDLE
        JC      @@1a
        CMP     RBX,U4 IDLE_START
        JB      @@1
        CMP     RBX,U4 IDLE_END
        JA      @@1
@@1a:   LOCK
        INC     U8 CPU_IDLE_POINT_HITS[RDI]

@@1:    MOV     RAX,U8 CPU_TIMER_IRQ_CHAIN[RDI]
        OR      RAX,RAX
        JZ      @@2
        PUSH    RSI
        CALL    RAX
        ADD     RSP,8
        CLI

@@2:    MOV     RAX,U8 CPU_NUM[RDI]
        OR      RAX,RAX
        JZ      @@3

        XOR     RAX,RAX
        MOV     EAX,U4 LAPIC_EOI
        MOV     U4 [RAX],0
        JMP     @@5

@@3:    MOV     AL,0x20                  //ACKNOWLEDGE INTERRUPT
        OUT     0x20,AL

@@5:    MOV     RAX,SYS_SEMAS
        BT      U4 SYS_SEMA_SINGLE_USER*SEMA_STRUCT_SIZE[RAX],0
        JC      @@5C
        BT      U8 TASK_TASK_FLAGS[RSI],TASKf_PREEMPT
        JC      I4 RESTORE_NEXT_RSI_TASK
@@5C:   LOCK
        BTR     U8 TASK_TASK_FLAGS[RSI],TASKf_HAS_BEEN_SWAPPED
        JC      @@5B
        LOCK
        INC     U8 CPU_NO_PREEMPT_HITS[RDI]
@@5B:   JMP     I4 RESTORE_RSI_NO_PREEMPT_TASK

IRQ00:: PUSH    0
        JMP     IRQFAULT_JMP

IRQ01:  PUSH    1
        JMP     IRQFAULT_JMP

//NMI
IRQ02:  HLT
        JMP     IRQ02

IRQ03:  PUSH    3
        JMP     IRQFAULT_JMP

IRQ04:  PUSH    4
        JMP     IRQFAULT_JMP

IRQ05:  PUSH    5
        JMP     IRQFAULT_JMP

IRQ06:  PUSH    6
        JMP     IRQFAULT_JMP

IRQ07:  PUSH    7
        JMP     IRQFAULT_JMP

IRQ08:  PUSH    8
        JMP     IRQFAULT_JMP

IRQ09:  PUSH    9
        JMP     IRQFAULT_JMP

IRQ0A:  PUSH    0x0A
        JMP     IRQFAULT_JMP

IRQ0B:  PUSH    0x0B
        JMP     IRQFAULT_JMP

IRQ0C:  PUSH    0x0C
        JMP     IRQFAULT_JMP

IRQ0D:  PUSH    0x0D
        JMP     IRQFAULT_JMP

IRQ0E:  PUSH    0x0E
        JMP     IRQFAULT_JMP

IRQ0F:  PUSH    0x0F
        JMP     IRQFAULT_JMP

IRQ10:  PUSH    0x10
IRQFAULT_JMP:
        JMP     IRQFAULT

IRQ11:  PUSH    0x11
        JMP     IRQFAULT

IRQ12:  PUSH    0x12
        JMP     IRQFAULT

IRQ13:  PUSH    0x13
        JMP     IRQFAULT

IRQ14:  PUSH    0x14
        JMP     IRQFAULT

IRQ15:  PUSH    0x15
        JMP     IRQFAULT

IRQ16:  PUSH    0x16
        JMP     IRQFAULT

IRQ17:  PUSH    0x17
        JMP     IRQFAULT

IRQ18:  PUSH    0x18
        JMP     IRQFAULT

IRQ19:  PUSH    0x19
        JMP     IRQFAULT

IRQ1A:  PUSH    0x1A
        JMP     IRQFAULT

IRQ1B:  PUSH    0x1B
        JMP     IRQFAULT

IRQ1C:  PUSH    0x1C
        JMP     IRQFAULT

IRQ1D:  PUSH    0x1D
        JMP     IRQFAULT

IRQ1E:  PUSH    0x1E
        JMP     IRQFAULT

IRQ1F:  PUSH    0x1F
        JMP     IRQFAULT

IRQ21:  PUSH    0x21
        JMP     IRQFAULT

IRQ22:  PUSH    0x22
        JMP     IRQFAULT

IRQ23:  PUSH    0x23
        JMP     IRQFAULT

IRQ24:  PUSH    0x24
        JMP     IRQFAULT

IRQ25:  PUSH    0x25
        JMP     IRQFAULT

IRQ26:  PUSH    0x26
        JMP     IRQFAULT

//This might be a spurious interrupt
//TODO:  Why is this needed?
IRQ27:  PUSH    RAX
        MOV     AL,0x20
        OUT     0x20,AL
        POP     RAX
        IRET

IRQ28:  PUSH    0x28
        JMP     IRQFAULT

IRQ29:  PUSH    0x29
        JMP     IRQFAULT

IRQ2A:  PUSH    0x2A
        JMP     IRQFAULT

IRQ2B:  PUSH    0x2B
        JMP     IRQFAULT

IRQ2C:  PUSH    0x2C
        JMP     IRQFAULT

IRQ2D:  PUSH    0x2D
        JMP     IRQFAULT

IRQ2E:  PUSH    0x2E
        JMP     IRQFAULT

IRQ2F:  PUSH    0x2F
        JMP     IRQFAULT

// ************************************
IRQFAULT::
        PUSH    RBX
        MOV     RBX,U8 8[RSP]
        PUSH    RAX
        XOR     RAX,RAX
        MOV     FS:U4 TASK_FAULT_NUM[RAX],EBX
        POP     RAX
        POP     RBX
        ADD     RSP,8

        CALL    SAVE_CONTEXT

        XOR     RDX,RDX
        MOV     U8 TASK_FAULT_ERR_CODE[RSI],RDX
        MOV     EDX,U4 TASK_FAULT_NUM[RSI]
        BT      U8 [FAULT_ERR_CODE_BITMAP],RDX
        JNC     @@1
        POP     U8 TASK_FAULT_ERR_CODE[RSI]

@@1:    MOV     RBP,RSP
        MOV     RAX,U8 [RBP]
        MOV     U8 TASK_RIP[RSI],RAX
        MOV     RAX,U8 16[RBP]
        MOV     U8 TASK_RFLAGS[RSI],RAX
        MOV     RAX,U8 24[RBP]
        MOV     U8 TASK_RSP[RSI],RAX
        MOV     RSP,RAX
        MOV     RBP,TASK_RBP[RSI]
        MOV     RSI,TASK_RSI[RSI]
        CALL    _FAULT2 //See _FAULT2
        JMP     I4 RESTORE_FS_TASK_WITH_KEY_CHECK

FAULT_ERR_CODE_BITMAP::
        DU4     0x00027D00;
}

asm {_INIT_IDT::}
U0 IDTInit()
{ //interrupt descriptor table
  U8 i,temp_ptr[2];
  U4 *src=IRQ_VECTORS,*dst;
  dst=Gs->idt=CAlloc(16*256);
  for (i=0;i<MAX_INITIAL_IDT;i++) {
    *dst><(U2 *)++=*src><(U2 *)++;
    *dst><(U2 *)++=SYS_CS64_SEL;
    *dst><(U2 *)++=0x8E00; //E=32-bit irq gate
    *dst><(U2 *)++=*src><(U2 *)++;
    *dst><(U8 *)++=0;
  }
  dst=temp_ptr;
  *dst><(U2 *)++=256*16-1;
  *dst><(U4 *)++=Gs->idt><(U8).u4[0];
  *dst><(U4 *)++=Gs->idt><(U8).u4[1];
  *dst><(U2 *)++=0;
  SetRAX(temp_ptr);
  asm {
        LIDT U8 [RAX]
  }
}

U0 *GetIDTEntry(U8 irq,U8 core_num)
{
  U8 result,*src=cpu_structs[core_num].idt><(U1 *)+irq*16;
  result.u2[0]=*src><(U2 *);
  src><(U1 *)+=6;
  result.u2[1]=*src><(U2 *)++;
  result.u4[1]=*src><(U4 *);
  return result;
}

U0 *SetIDTEntry(U8 irq,U0 (*fp_new_handler)(),U8 core_num)
{
//See ::/LT/Doc/Lectures/Interrupts.CPZ
//See ::/LT/Demo/MultiCore/Interrupts.CPZ
  U8 result=GetIDTEntry(irq,core_num);
  U1 *dst=cpu_structs[core_num].idt><(U1 *)+irq*16;
  *dst><(U2 *)++=fp_new_handler><(U8).u2[0];
  *dst><(U2 *)++=SYS_CS64_SEL;
  *dst><(U2 *)++=0x8E00; //E=32-bit irq gate
  *dst><(U2 *)++=fp_new_handler><(U8).u2[1];
  *dst><(U4 *)++=fp_new_handler><(U8).u4[1];
  *dst><(U4 *)++=0;
  return result;
}