242 lines
5.3 KiB
C++
242 lines
5.3 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_SAVE_CONTEXT //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
|
|
JC @@05
|
|
CMP RBX,U32 SYS_IDLE_START
|
|
JB @@10
|
|
CMP RBX,U32 SYS_IDLE_END
|
|
JA @@10
|
|
@@05: LOCK
|
|
INC U64 CCPU.idle_pt_hits[RDI]
|
|
|
|
@@10: MOV RAX,U64 CCPU.timer_irq_chain[RDI]
|
|
OR RAX,RAX
|
|
JZ @@15
|
|
PUSH RSI
|
|
CALL RAX
|
|
JMP @@20
|
|
@@15: ADD RSP,8
|
|
@@20: CLI
|
|
MOV RAX,U64 CCPU.num[RDI]
|
|
OR RAX,RAX
|
|
JZ @@25
|
|
|
|
MOV EAX,U32 LAPIC_EOI
|
|
MOV U32 [RAX],0
|
|
JMP @@30
|
|
|
|
@@25: MOV AL,0x20 //ACKNOWLEDGE INTERRUPT
|
|
OUT 0x20,AL
|
|
|
|
@@30: MOV RAX,SYS_SEMAS
|
|
BT U32 SYS_SEMA_SINGLE_USER*SEMA_STRUCT_SIZE[RAX],0
|
|
JC @@35
|
|
BT U64 CTask.task_flags[RSI],TASKf_PREEMPT
|
|
JC I32 RESTORE_NEXT_RSI_TASK
|
|
@@35: 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_SAVE_CONTEXT
|
|
|
|
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]
|
|
MOV RSI,CTask.rsi[RSI]
|
|
CALL &Fault2 //See $LK,"Fault2","FF:::/SparrowOS/OSMain/Dbg1a.CPP.Z,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,I64 cpu_num=-1)
|
|
{
|
|
U8 *result;
|
|
I64 *src;
|
|
if (cpu_num<0) cpu_num=Gs->num;
|
|
if (cpu_num>=mp_cnt&&cpu_num>Gs->num)
|
|
throw(EXCEPT_MULTICORE,3);
|
|
src=cpu_structs[cpu_num].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 cpu_num=-1,
|
|
I64 type=IDTET_IRQ,I64 dpl=0)
|
|
{
|
|
//See $LK,"IDTET_IRQ","MN:IDTET_IRQ"$
|
|
//See $LK,"::/SparrowOS/Demo/Lectures/InterruptDemo.CPP.Z","FI:::/SparrowOS/Demo/Lectures/InterruptDemo.CPP.Z"$
|
|
//See $LK,"::/SparrowOS/Demo/MultiCore/Interrupts.CPP.Z","FI:::/SparrowOS/Demo/MultiCore/Interrupts.CPP.Z"$
|
|
I64 fp=fp_new_handler;
|
|
U8 *result,*dst;
|
|
|
|
if (cpu_num<0) cpu_num=Gs->num;
|
|
|
|
result=IntEntryGet(irq,cpu_num);
|
|
dst=cpu_structs[cpu_num].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 IntNop1()
|
|
{ //Make unplanned IRQs stop!
|
|
//IRQs on cores other than zero are APIC, I'm pretty sure.
|
|
//I think the PIC only generates core 0 IRQs.
|
|
IntEOI;
|
|
}
|
|
|
|
interrupt U0 IntNop2()
|
|
{ //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;
|
|
Gs->idt=CAlloc(16*256);
|
|
/*
|
|
During boot, we don't know what hardware PIC IRQ's were set to.
|
|
When we unmask for the first time, after initializing the PIC, I'm
|
|
not sure of old pending IRQs will be issued.
|
|
|
|
After boot, we might get a APIC IRQ because we never initialize that.
|
|
Acknowledging unplanned IRQs seems safest to me, even
|
|
if we accidentally turn-off a valid IRQ and miss it.
|
|
We only support keyboard, mouse and timer, anyway.
|
|
*/
|
|
for (i=0;i<256;i++)
|
|
if (!Gs->num)
|
|
IntEntrySet(i,&IntNop2);
|
|
else
|
|
IntEntrySet(i,&IntNop1);
|
|
|
|
ptr=temp_ptr;
|
|
*ptr(U16 *)++=256*16-1;
|
|
*ptr(U32 *)++=Gs->idt(I64).u32[0];
|
|
*ptr(U32 *)++=Gs->idt(I64).u32[1];
|
|
*ptr(U16 *)++=0;
|
|
SetRAX(temp_ptr);
|
|
asm { LIDT U64 [RAX] }
|
|
}
|
|
|
|
U0 IntInit2()
|
|
{ //Interrupt descriptor table part2
|
|
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,"IntNop2","MN:IntNop2"$().
|
|
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);
|
|
PopFD;
|
|
}
|