ZealOS/src/Kernel/KInterrupts.CC
2020-02-16 12:37:19 -06:00

215 lines
4.8 KiB
HolyC
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

asm {
INT_MP_CRASH_ADDR:: //Forward reference to work around compiler
DU32 &IntMPCrash;
INT_WAKE::
PUSH RDX
PUSH RAX
MOV EAX,&dev
MOV EDX,U32 LAPIC_EOI
MOV RAX,U64 CDevGlobals.uncached_alias[RAX]
MOV U32 [RAX+RDX],0
POP RAX
POP RDX
IRET
IRQ_TIMER:: //I_TIMER
CALL TASK_CONTEXT_SAVE
CLD
MOV RAX,U64 [RSP]
MOV U64 CTask.rip[RSI],RAX
MOV RAX,U64 16[RSP]
MOV U64 CTask.rflags[RSI],RAX
MOV RAX,U64 24[RSP]
MOV U64 CTask.rsp[RSI],RAX
XOR RAX,RAX
MOV RDI,U64 GS:CCPU.addr[RAX]
LOCK
INC U64 CCPU.total_jiffies[RDI]
BT U64 CTask.task_flags[RSI],TASKf_IDLE
JNC @@05
LOCK
INC U64 CCPU.idle_pt_hits[RDI]
@@05: MOV RAX,U64 CCPU.profiler_timer_irq[RDI]
TEST RAX,RAX
JZ @@10
PUSH RSI
CALL RAX //See $LK,"ProfTimerInt",A="MN:ProfTimerInt"$().
JMP @@15
@@10: ADD RSP,8
@@15: CLI
MOV RAX,U64 CCPU.num[RDI]
TEST RAX,RAX
JZ @@20
MOV EAX,&dev
MOV EDX,U32 LAPIC_EOI
MOV RAX,U64 CDevGlobals.uncached_alias[RAX]
MOV U32 [RAX+RDX],0
JMP @@25
@@20: CALL &IntCore0TimerHandler //Only Core 0 calls this.
@@25: XOR RAX,RAX
CMP RSI,U64 GS:CCPU.idle_task[RAX]
JE I32 RESTORE_SETH_TASK_IF_READY
JMP I32 RESTORE_RSI_TASK
//************************************
INT_FAULT::
PUSH RBX
PUSH RAX
MOV BL,U8 16[RSP] //We pushed fault_num $LK,"IntFaultHandlersNew",A="MN:IntFaultHandlersNew"$().
XOR RAX,RAX
MOV FS:U8 CTask.fault_num[RAX],BL
POP RAX
POP RBX
ADD RSP,8 //Pop fault_num
CALL TASK_CONTEXT_SAVE
XOR RDX,RDX
MOV U64 CTask.fault_err_code[RSI],RDX
MOV EDX,U32 CTask.fault_num[RSI]
BT U64 [INT_FAULT_ERR_CODE_BITMAP],RDX
JNC @@1
POP U64 CTask.fault_err_code[RSI]
@@1: MOV RAX,U64 [RSP]
MOV U64 CTask.rip[RSI],RAX
MOV RAX,U64 16[RSP]
MOV U64 CTask.rflags[RSI],RAX
MOV RSP,U64 24[RSP]
MOV U64 CTask.rsp[RSI],RSP
MOV RBP,CTask.rbp[RSI]
PUSH U64 CTask.fault_err_code[RSI]
PUSH U64 CTask.fault_num[RSI]
MOV RSI,CTask.rsi[RSI]
CALL &Fault2 //See $LK,"Fault2",A="FF:::/Kernel/KDebug.CC,Fault2"$
JMP I32 RESTORE_FS_TASK
INT_FAULT_ERR_CODE_BITMAP::
DU32 0x00027D00,0,0,0,0,0,0,0;
}
U8 *IntEntryGet(I64 irq)
{//Get interrupt vector.
U8 *res;
I64 *src;
src=dev.idt(U8 *)+irq*16;
res(I64).u16[0]=*src(U16 *);
src(U8 *)+=6;
res(I64).u16[1]=*src(U16 *)++;
res(I64).u32[1]=*src(U32 *);
return res;
}
U8 *IntEntrySet(I64 irq,U0 (*fp_new_handler)(),I64 type=IDTET_IRQ,I64 dpl=0)
{//Set interrupt vector. See $LK,"IDTET_IRQ",A="MN:IDTET_IRQ"$.
//See $LK,"::/Demo/Lectures/InterruptDemo.CC"$.
//See $LK,"::/Demo/MultiCore/Interrupts.CC"$.
I64 fp=fp_new_handler;
U8 *res,*dst;
PUSHFD
CLI
res=IntEntryGet(irq);
dst=dev.idt(U8 *)+irq*16;
*dst(U16 *)++=fp.u16[0];
*dst(U16 *)++=offset(CGDT.cs64);
*dst(U16 *)++=0x8000+type<<8+dpl<<13;
*dst(U16 *)++=fp.u16[1];
*dst(U32 *)++=fp.u32[1];
*dst(U32 *)=0;
POPFD
return res;
}
U0 IntsInit()
{//Init 8259
OutU8(PIC1,0x11); //IW1
OutU8(PIC2,0x11); //IW1
OutU8(PIC1_DATA,0x20); //IW2
OutU8(PIC2_DATA,0x28); //IW2
OutU8(PIC1_DATA,0x04); //IW3
OutU8(PIC2_DATA,0x02); //IW3
OutU8(PIC1_DATA,0x0D); //IW4
OutU8(PIC2_DATA,0x09); //IW4
OutU8(PIC1_DATA,0xFA); //Mask all but IRQ0 (timer) and IRQ2 Cascade.
OutU8(PIC2_DATA,0xFF);
}
interrupt U0 IntNop()
{//Make unplanned IRQs stop by all means!
OutU8(PIC2,PIC_EOI);
OutU8(PIC1,PIC_EOI);
 *(dev.uncached_alias + LAPIC_EOI)(U32 *) = 0;
}
interrupt U0 IntDivZero()
{
if (Gs->num) {
mp_count=1;
debug.mp_crash->cpu_num=Gs->num;
debug.mp_crash->task=Fs;
MOV RAX,U64 8[RBP] //Get RIP off of stack.
debug.mp_crash->rip=GetRAX;
debug.mp_crash->message="Div Zero";
debug.mp_crash->message_num=0;
MPInt(I_MP_CRASH,0);
SysHlt;
}
throw('DivZero');
}
U8 *IntFaultHandlersNew()
{
I64 i;
U8 *res=MAlloc(256*7,Fs->code_heap),*dst=res;
for (i=0;i<256;i++) {
*dst++=0x6A; //PUSH I8 xx
*dst(I8 *)++=i;
*dst++=0xE9; //JMP I32 xxxxxxxx
*dst(I32 *)=INT_FAULT-dst-4;
dst+=4;
}
return res;
}
U0 IntInit1()
{//Interrupt descriptor table part1.
I64 i;
CSysLimitBase tmp_ptr;
if (!Gs->num) {//Gs cur $LK,"CCPU",A="MN:CCPU"$ struct
dev.idt=CAlloc(16*256);
for (i=0;i<256;i++)
IntEntrySet(i,&IntNop);
}
tmp_ptr.limit=256*16-1;
tmp_ptr.base =dev.idt;
SetRAX(&tmp_ptr);
LIDT U64 [RAX]
}
U0 IntInit2()
{//Interrupt descriptor table part2: Core 0 Only.
I64 i;
PUSHFD
CLI
IntEntrySet(I_DIV_ZERO,&IntDivZero);
for (i=1;i<0x20;i++)
IntEntrySet(i,&debug.int_fault_code[7*i]);
/*In theory, we use the PIC mask reg to insure we don't get
anything but keyboard, mouse and timer IRQs. In practice, I've
gotten IRQ 0x27, perhaps because I didn't initialize the APIC.
I go ahead and ACK PIC in $LK,"IntNop",A="MN:IntNop"$().
I have no idea why I got a IRQ 0x27.
*/
IntEntrySet(I_NMI,_SYS_HLT);
IntEntrySet(I_TIMER,IRQ_TIMER);
IntEntrySet(I_MP_CRASH,*INT_MP_CRASH_ADDR(U32 *));
IntEntrySet(I_WAKE,INT_WAKE);
IntEntrySet(I_DEBUG,&debug.int_fault_code[7*I_DEBUG]);
POPFD
}