1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
|
;------------------------------------------------------------------------------ ;
; Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution. The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php.
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;
; Module Name:
;
; MpFuncs.nasm
;
; Abstract:
;
; This is the assembly code for MP support
;
;-------------------------------------------------------------------------------
%include "MpEqu.inc"
extern ASM_PFX(InitializeFloatingPointUnits)
SECTION .text
;-------------------------------------------------------------------------------------
;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
;procedure serializes all the AP processors through an Init sequence. It must be
;noted that APs arrive here very raw...ie: real mode, no stack.
;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
;IS IN MACHINE CODE.
;-------------------------------------------------------------------------------------
global ASM_PFX(RendezvousFunnelProc)
ASM_PFX(RendezvousFunnelProc):
RendezvousFunnelProcStart:
; At this point CS = 0x(vv00) and ip= 0x0.
BITS 16
mov ebp, eax ; save BIST information
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
xor ax, ax
mov fs, ax
mov gs, ax
mov si, BufferStartLocation
mov ebx, [si]
mov si, ModeOffsetLocation
mov eax, [si]
mov si, CodeSegmentLocation
mov edx, [si]
mov di, ax
sub di, 02h
mov [di], dx
sub di, 04h
add eax, ebx
mov [di],eax
mov si, DataSegmentLocation
mov edx, [si]
mov si, GdtrLocation
o32 lgdt [cs:si]
mov si, IdtrLocation
o32 lidt [cs:si]
xor ax, ax
mov ds, ax
mov eax, cr0 ; Get control register 0
or eax, 000000003h ; Set PE bit (bit #0) & MP
mov cr0, eax
jmp 0:strict dword 0 ; far jump to protected mode
BITS 32
Flat32Start: ; protected mode entry point
mov ds, dx
mov es, dx
mov fs, dx
mov gs, dx
mov ss, dx
mov esi, ebx
mov edi, esi
add edi, EnableExecuteDisableLocation
cmp byte [edi], 0
jz SkipEnableExecuteDisable
;
; Enable IA32 PAE execute disable
;
mov ecx, 0xc0000080
rdmsr
bts eax, 11
wrmsr
mov edi, esi
add edi, Cr3Location
mov eax, dword [edi]
mov cr3, eax
mov eax, cr4
bts eax, 5
mov cr4, eax
mov eax, cr0
bts eax, 31
mov cr0, eax
SkipEnableExecuteDisable:
mov edi, esi
add edi, InitFlagLocation
cmp dword [edi], 1 ; 1 == ApInitConfig
jnz GetApicId
; AP init
mov edi, esi
add edi, LockLocation
mov eax, NotVacantFlag
TestLock:
xchg [edi], eax
cmp eax, NotVacantFlag
jz TestLock
mov ecx, esi
add ecx, NumApsExecutingLocation
inc dword [ecx]
mov ebx, [ecx]
Releaselock:
mov eax, VacantFlag
xchg [edi], eax
mov edi, esi
add edi, StackSizeLocation
mov eax, [edi]
mov ecx, ebx
inc ecx
mul ecx ; EAX = StackSize * (CpuNumber + 1)
mov edi, esi
add edi, StackStartAddressLocation
add eax, [edi]
mov esp, eax
jmp CProcedureInvoke
GetApicId:
mov eax, 0
cpuid
cmp eax, 0bh
jnb X2Apic
; Processor is not x2APIC capable, so get 8-bit APIC ID
mov eax, 1
cpuid
shr ebx, 24
mov edx, ebx
jmp GetProcessorNumber
X2Apic:
; Processor is x2APIC capable, so get 32-bit x2APIC ID
mov eax, 0bh
xor ecx, ecx
cpuid
; edx save x2APIC ID
GetProcessorNumber:
;
; Get processor number for this AP
; Note that BSP may become an AP due to SwitchBsp()
;
xor ebx, ebx
lea eax, [esi + CpuInfoLocation]
mov edi, [eax]
GetNextProcNumber:
cmp [edi], edx ; APIC ID match?
jz ProgramStack
add edi, 20
inc ebx
jmp GetNextProcNumber
ProgramStack:
mov esp, [edi + 12]
CProcedureInvoke:
push ebp ; push BIST data at top of AP stack
xor ebp, ebp ; clear ebp for call stack trace
push ebp
mov ebp, esp
mov eax, ASM_PFX(InitializeFloatingPointUnits)
call eax ; Call assembly function to initialize FPU per UEFI spec
push ebx ; Push NumApsExecuting
mov eax, esi
add eax, LockLocation
push eax ; push address of exchange info data buffer
mov edi, esi
add edi, ApProcedureLocation
mov eax, [edi]
call eax ; Invoke C function
jmp $ ; Never reach here
RendezvousFunnelProcEnd:
;-------------------------------------------------------------------------------------
; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment);
;-------------------------------------------------------------------------------------
global ASM_PFX(AsmRelocateApLoop)
ASM_PFX(AsmRelocateApLoop):
AsmRelocateApLoopStart:
cmp byte [esp + 4], 1
jnz HltLoop
MwaitLoop:
mov eax, esp
xor ecx, ecx
xor edx, edx
monitor
mov eax, [esp + 8] ; Mwait Cx, Target C-State per eax[7:4]
shl eax, 4
mwait
jmp MwaitLoop
HltLoop:
cli
hlt
jmp HltLoop
ret
AsmRelocateApLoopEnd:
;-------------------------------------------------------------------------------------
; AsmGetAddressMap (&AddressMap);
;-------------------------------------------------------------------------------------
global ASM_PFX(AsmGetAddressMap)
ASM_PFX(AsmGetAddressMap):
pushad
mov ebp,esp
mov ebx, [ebp + 24h]
mov dword [ebx], RendezvousFunnelProcStart
mov dword [ebx + 4h], Flat32Start - RendezvousFunnelProcStart
mov dword [ebx + 8h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
mov dword [ebx + 0Ch], AsmRelocateApLoopStart
mov dword [ebx + 10h], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
popad
ret
;-------------------------------------------------------------------------------------
;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
;about to become an AP. It switches it'stack with the current AP.
;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
;-------------------------------------------------------------------------------------
global ASM_PFX(AsmExchangeRole)
ASM_PFX(AsmExchangeRole):
; DO NOT call other functions in this function, since 2 CPU may use 1 stack
; at the same time. If 1 CPU try to call a function, stack will be corrupted.
pushad
mov ebp,esp
; esi contains MyInfo pointer
mov esi, [ebp + 24h]
; edi contains OthersInfo pointer
mov edi, [ebp + 28h]
;Store EFLAGS, GDTR and IDTR register to stack
pushfd
mov eax, cr4
push eax ; push cr4 firstly
mov eax, cr0
push eax
sgdt [esi + 8]
sidt [esi + 14]
; Store the its StackPointer
mov [esi + 4],esp
; update its switch state to STORED
mov byte [esi], CPU_SWITCH_STATE_STORED
WaitForOtherStored:
; wait until the other CPU finish storing its state
cmp byte [edi], CPU_SWITCH_STATE_STORED
jz OtherStored
pause
jmp WaitForOtherStored
OtherStored:
; Since another CPU already stored its state, load them
; load GDTR value
lgdt [edi + 8]
; load IDTR value
lidt [edi + 14]
; load its future StackPointer
mov esp, [edi + 4]
; update the other CPU's switch state to LOADED
mov byte [edi], CPU_SWITCH_STATE_LOADED
WaitForOtherLoaded:
; wait until the other CPU finish loading new state,
; otherwise the data in stack may corrupt
cmp byte [esi], CPU_SWITCH_STATE_LOADED
jz OtherLoaded
pause
jmp WaitForOtherLoaded
OtherLoaded:
; since the other CPU already get the data it want, leave this procedure
pop eax
mov cr0, eax
pop eax
mov cr4, eax
popfd
popad
ret
|