|
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\nkernsmp\x86\vectors.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include <x86.h> |
|
19 #include <apic.h> |
|
20 #include <nk_irq.h> |
|
21 #include "vectors.h" |
|
22 |
|
23 TUint32 __tr(); |
|
24 void __ltr(TInt); |
|
25 |
|
26 extern "C" void _irqdebug(TUint a) |
|
27 { |
|
28 if (a>=0x30) |
|
29 return; |
|
30 __KTRACE_OPT(KSCHED2,DEBUGPRINT("!%02x",a)); |
|
31 } |
|
32 |
|
33 extern "C" void IrqStartTrace(TUint32 aVector) |
|
34 { |
|
35 __ACQUIRE_BTRACE_LOCK(); |
|
36 BTraceData.iHandler(BTRACE_HEADER(8,BTrace::ECpuUsage,BTrace::EIrqStart),0,0,aVector,0,0,0,0); |
|
37 __RELEASE_BTRACE_LOCK(); |
|
38 } |
|
39 |
|
40 extern "C" void IrqEndTrace() |
|
41 { |
|
42 __ACQUIRE_BTRACE_LOCK(); |
|
43 BTraceData.iHandler(BTRACE_HEADER(4,BTrace::ECpuUsage,BTrace::EIrqEnd),0,0,0,0,0,0,0); |
|
44 __RELEASE_BTRACE_LOCK(); |
|
45 } |
|
46 |
|
47 |
|
48 /** Register the global IRQ handler |
|
49 Called by the base port at boot time to bind the top level IRQ dispatcher |
|
50 to the X86 common IRQ handler. Should not be called at any other time. |
|
51 |
|
52 The handler specified will be called with IRQs disabled. ESP will point |
|
53 to the top of the interrupt stack. On entry to the handler EAX will point |
|
54 to a block of saved registers, as follows: |
|
55 |
|
56 [EAX+00h] = saved ESI |
|
57 [EAX+04h] = saved EDI |
|
58 [EAX+08h] = saved EDX |
|
59 [EAX+0Ch] = saved ECX |
|
60 [EAX+10h] = saved EAX |
|
61 [EAX+14h] = saved ES |
|
62 [EAX+18h] = saved DS |
|
63 [EAX+1Ch] = interrupt vector number |
|
64 [EAX+20h] = return EIP |
|
65 [EAX+24h] = return CS |
|
66 [EAX+28h] = return EFLAGS |
|
67 [EAX+2Ch] = return ESP if interrupt occurred while CPL>0 |
|
68 [EAX+30h] = return SS if interrupt occurred while CPL>0 |
|
69 |
|
70 The handler should preserve all registers other than EAX, ECX, EDX |
|
71 and should return using a standard RET instruction. |
|
72 |
|
73 @param aHandler The address of the top level IRQ dispatcher routine |
|
74 */ |
|
75 EXPORT_C void X86::SetIrqHandler(TLinAddr aHandler) |
|
76 { |
|
77 X86_IrqHandler = aHandler; |
|
78 } |
|
79 |
|
80 |
|
81 /** Return the address immediately after the end of the interrupt stack. |
|
82 |
|
83 @return Interrupt Stack Base + Interrupt Stack Size |
|
84 */ |
|
85 EXPORT_C TLinAddr X86::IrqStackTop(TInt aCpu) |
|
86 { |
|
87 TLinAddr a = 0; |
|
88 if (aCpu>=0 && aCpu<KMaxCpus) |
|
89 a = TLinAddr(TheSubSchedulers[aCpu].i_IrqStackTop); |
|
90 else |
|
91 { |
|
92 TInt irq = NKern::DisableAllInterrupts(); |
|
93 a = TLinAddr(SubScheduler().i_IrqStackTop); |
|
94 NKern::RestoreInterrupts(irq); |
|
95 } |
|
96 return a; |
|
97 } |
|
98 |
|
99 void SetTrapGate(SX86Des* aEntry, PFV aHandler, TInt aDPL) |
|
100 { |
|
101 aEntry->iLow=(KRing0CS<<16)|(TUint32(aHandler)&0xffff); |
|
102 aEntry->iHigh=(TUint32(aHandler)&0xffff0000) | 0x8f00 | (aDPL<<13); |
|
103 } |
|
104 |
|
105 void SetInterruptGate(SX86Des* aEntry, PFV aHandler, TInt aDPL) |
|
106 { |
|
107 aEntry->iLow=(KRing0CS<<16)|(TUint32(aHandler)&0xffff); |
|
108 aEntry->iHigh=(TUint32(aHandler)&0xffff0000) | 0x8e00 | (aDPL<<13); |
|
109 } |
|
110 |
|
111 void SetTssDescriptor(SX86Des* aEntry, TX86Tss* aTss) |
|
112 { |
|
113 TUint addr3=TUint(aTss)>>24; |
|
114 TUint addr2=(TUint(aTss)>>16)&0xff; |
|
115 TUint addr01=TUint(aTss)&0xffff; |
|
116 aEntry->iLow=(addr01<<16)|(sizeof(TX86Tss)-1); |
|
117 aEntry->iHigh=(addr3<<24)|0x00108900|addr2; |
|
118 } |
|
119 |
|
120 void X86::Init1Interrupts() |
|
121 // |
|
122 // Initialise the interrupt and exception vector handlers. |
|
123 // |
|
124 { |
|
125 // TheIrqHandler=0; // done by placing TheIrqHandler, TheFiqHandler in .bss |
|
126 __KTRACE_OPT(KBOOT,DEBUGPRINT(">X86::Init1Interrupts()")); |
|
127 |
|
128 TCpuPages& cp=X86::CpuPage(); |
|
129 memclr(cp.iIdt, KIdtSize*sizeof(SX86Des)); |
|
130 TInt i; |
|
131 for (i=0; i<(TInt)(sizeof(TheExcVectors)/sizeof(PFV)); i++) |
|
132 { |
|
133 if (i==0x03 || i==0x20 || i==0x21) |
|
134 SetInterruptGate(cp.iIdt+i, TheExcVectors[i], 3); |
|
135 else if (i<0x20 && i!=0x02) |
|
136 SetInterruptGate(cp.iIdt+i, TheExcVectors[i], 0); |
|
137 if (i==0x02 || i>=0x27) |
|
138 SetInterruptGate(cp.iIdt+i, TheExcVectors[i], 0); |
|
139 } |
|
140 for (i=0; i<KMaxCpus; ++i) |
|
141 { |
|
142 SCpuData& cd = cp.iCpuData[i]; |
|
143 memclr(&cd, sizeof(cd) - sizeof(cd.iIrqStack)); |
|
144 memset(cd.iIrqStack, 0xab+i*2, sizeof(cd.iIrqStack)); |
|
145 |
|
146 TUint32 esp = (TUint32)cd.iIrqStack + sizeof(cd.iIrqStack); |
|
147 cd.iTss.iCR3 = get_cr3(); |
|
148 cd.iTss.iSs0 = KRing0DS; |
|
149 cd.iTss.iEsp0 = esp; |
|
150 SetTssDescriptor(&cp.iGdt[5+i], &cd.iTss); |
|
151 |
|
152 TSubScheduler& ss = TheSubSchedulers[i]; |
|
153 ss.i_IrqNestCount = (TAny*)(-1); |
|
154 ss.i_IrqStackTop = (TAny*)esp; |
|
155 ss.i_Tss = &cd.iTss; |
|
156 } |
|
157 |
|
158 X86::DefaultCR0 = get_cr0(); |
|
159 NIrq::HwInit1(); |
|
160 |
|
161 __ltr(TSS_SELECTOR(0)); |
|
162 __lidt(cp.iIdt, KIdtSize); |
|
163 __KTRACE_OPT(KBOOT,DEBUGPRINT("<X86::Init1Interrupts()")); |
|
164 } |
|
165 |
|
166 |
|
167 extern "C" void ExcFault(TAny*); |
|
168 void __X86ExcFault(TAny* aInfo) |
|
169 { |
|
170 ExcFault(aInfo); |
|
171 } |
|
172 |