Files
TempleOS-Rijn/TempleOS/Kernel/Interrupts.CPP
T
2018-09-08 21:45:37 +02:00

214 lines
4.4 KiB
C++

asm {
USE64
SYS_MP_CRASH_HANDLER_ADDR:: //forward reference to work around compiler
DU32 &MPCrash;
SYS_WAKE_HANDLER::
PUSH RAX
MOV EAX,U32 LAPIC_EOI
MOV U32 [RAX],0
POP RAX
IRET
//I_TIMER
SYS_TIMER_HANDLER::
CALL SYS_CONTEXT_SAVE //PREEMPTIVE
CLD
MOV RBP,RSP
MOV RBX,U64 [RBP]
MOV U64 CTask.rip[RSI],RBX
MOV RAX,U64 16[RBP]
MOV U64 CTask.rflags[RSI],RAX
MOV RAX,U64 24[RBP]
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.timer_irq_chain[RDI]
OR RAX,RAX
JZ @@10
PUSH RSI
CALL RAX
JMP @@15
@@10: ADD RSP,8
@@15: CLI
MOV RAX,U64 CCPU.num[RDI]
OR RAX,RAX
JZ @@20
MOV EAX,U32 LAPIC_EOI
MOV U32 [RAX],0
JMP @@25
@@20: MOV AL,0x20 //ACKNOWLEDGE INTERRUPT
OUT 0x20,AL
@@25: MOV RAX,SYS_SEMAS
BT U32 SYS_SEMA_SINGLE_USER*SEMA_STRUCT_SIZE[RAX],0
JC @@30
BT U64 CTask.task_flags[RSI],TASKf_PREEMPT
JC I32 RESTORE_NEXT_RSI_TASK
@@30: JMP I32 RESTORE_RSI_NO_PREEMPT_TASK
// ************************************
SYS_IRQ_FAULT::
PUSH RBX
MOV RBX,U64 8[RSP]
PUSH RAX
XOR RAX,RAX
MOV FS:U32 CTask.fault_num[RAX],EBX
POP RAX
POP RBX
ADD RSP,8
CALL SYS_CONTEXT_SAVE
XOR RDX,RDX
MOV U64 CTask.fault_err_code[RSI],RDX
MOV EDX,U32 CTask.fault_num[RSI]
BT U64 [SYS_FAULT_ERR_CODE_BITMAP],RDX
JNC @@1
POP U64 CTask.fault_err_code[RSI]
@@1: MOV RBP,RSP
MOV RAX,U64 [RBP]
MOV U64 CTask.rip[RSI],RAX
MOV RAX,U64 16[RBP]
MOV U64 CTask.rflags[RSI],RAX
MOV RAX,U64 24[RBP]
MOV U64 CTask.rsp[RSI],RAX
MOV RSP,RAX
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","FF:::/TempleOS/Kernel/Dbg1a.CPP,Fault2"$
JMP I32 RESTORE_FS_TASK_WITH_KEY_CHECK
SYS_FAULT_ERR_CODE_BITMAP::
DU32 0x00027D00,0,0,0,0,0,0,0;
}
U8 *IntEntryGet(I64 irq)
{
U8 *result;
I64 *src;
src=sys_idt(U8 *)+irq*16;
result(I64).u16[0]=*src(U16 *);
src(U8 *)+=6;
result(I64).u16[1]=*src(U16 *)++;
result(I64).u32[1]=*src(U32 *);
return result;
}
U8 *IntEntrySet(I64 irq,U0 (*fp_new_handler)(),I64 type=IDTET_IRQ,I64 dpl=0)
{
//See $LK,"IDTET_IRQ","MN:IDTET_IRQ"$
//See $LK-A,"::/TempleOS/Demo/Lectures/InterruptDemo.CPP"$
//See $LK-A,"::/TempleOS/Demo/MultiCore/Interrupts.CPP"$
I64 fp=fp_new_handler;
U8 *result,*dst;
result=IntEntryGet(irq);
dst=sys_idt(U8 *)+irq*16;
PushFD;
Cli;
*dst(U16 *)++=fp.u16[0];
*dst(U16 *)++=GDT_CS64_SEL;
*dst(U16 *)++=0x8000+type<<8+dpl<<13;
*dst(U16 *)++=fp.u16[1];
*dst(U32 *)++=fp.u32[1];
*dst(U32 *)++=0;
PopFD;
return result;
}
U0 IntsInit()
{
//Init 8259
OutU8(0x20,0x11); //IW1
OutU8(0xA0,0x11); //IW1
OutU8(0x21,0x20); //IW2
OutU8(0xA1,0x28); //IW2
OutU8(0x21,0x04); //IW3
OutU8(0xA1,0x02); //IW3
OutU8(0x21,0x0D); //IW4
OutU8(0xA1,0x09); //IW4
OutU8(0x21,0xFA); //Mask all but IRQ0 (timer) and IRQ2 Cascade
OutU8(0xA1,0xFF);
}
U0 IntEOI()
{
*LAPIC_EOI(U32 *)=0;
}
interrupt U0 IntNop()
{ //Make unplanned IRQs stop by all means!
OutU8(0xA0,0x20);
OutU8(0x20,0x20);
IntEOI;
}
U8 *IntFaultHandlersNew()
{
I64 i;
U8 *result=MAlloc(256*10,Fs->code_heap),*dst=result;
for (i=0;i<256;i++) {
*dst++=0x68; //PUSH I32 xxxxxxxx
*dst(I32 *)++=i;
*dst++=0xE9; //JMP I32 xxxxxxxx
*dst(I32 *)=SYS_IRQ_FAULT-dst-4;
dst+=4;
}
return result;
}
U0 IntInit1()
{ //Interrupt descriptor table part1
I64 i,temp_ptr[2];
U32 *ptr;
if (!Gs->num) {
sys_idt=CAlloc(16*256);
for (i=0;i<256;i++)
IntEntrySet(i,&IntNop);
}
ptr=temp_ptr;
*ptr(U16 *)++=256*16-1;
*ptr(U32 *)++=sys_idt(I64).u32[0];
*ptr(U32 *)++=sys_idt(I64).u32[1];
*ptr(U16 *)++=0;
SetRAX(temp_ptr);
asm { LIDT U64 [RAX] }
}
U0 IntInit2()
{ //Interrupt descriptor table part2: Core 0 Only
I64 i;
PushFD;
Cli;
for (i=0;i<0x20;i++)
IntEntrySet(i,&sys_fault_handlers_code[10*i]);
/*
In theory, we use the PIC mask register 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","MN:IntNop"$().
I have no idea why I got a IRQ 0x27.
*/
IntEntrySet(I_NMI,_SYS_HLT);
IntEntrySet(I_TIMER,SYS_TIMER_HANDLER);
IntEntrySet(I_MP_CRASH,*SYS_MP_CRASH_HANDLER_ADDR(U32 *));
IntEntrySet(I_WAKE,SYS_WAKE_HANDLER);
IntEntrySet(I_DBG,&sys_fault_handlers_code[10*I_DBG]);
PopFD;
}