summaryrefslogtreecommitdiff
path: root/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.s
blob: fd44beae0b0f10d2f24d654debeb707711e8c19f (plain)
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
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
## @file
#  This is the assembly code for MP (Multiple-processor) support.
#
#  Copyright (c) 1999 - 2015, 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.
#
##

##include Htequ.inc

.equ    VacantFlag       ,      0x00
.equ    NotVacantFlag    ,      0xff
.equ    StartupApSignal  ,      0x6E750000
.equ    MonitorFilterSize,      0x10
.equ    ApCounterInit    ,      0
.equ    ApInHltLoop      ,      1
.equ    ApInMwaitLoop    ,      2
.equ    ApInRunLoop      ,      3

.equ    LockLocation     ,      0x1000 - 0x0400
.equ    StackStart       ,      LockLocation + 0x4
.equ    StackSize        ,      LockLocation + 0x8
.equ    RendezvousProc   ,      LockLocation + 0x0C
.equ    GdtrProfile      ,      LockLocation + 0x10
.equ    IdtrProfile      ,      LockLocation + 0x16
.equ    BufferStart      ,      LockLocation + 0x1C
.equ    Cr3Location      ,      LockLocation + 0x20
.equ    InitFlag         ,      LockLocation + 0x24
.equ    WakeUpApManner   ,      LockLocation + 0x28
.equ    BistBuffer       ,      LockLocation + 0x2C

#-------------------------------------------------------------------------------------

.macro  PAUSE32
            .byte 0xF3
            .byte 0x90
.endm

.macro FJMP32 Selector, Offset
            .byte      0x066
            .byte      0x067
            .byte      0x0EA            # far jump
            .long      \Offset          # 32-bit offset
            .word      \Selector        # 16-bit selector
.endm

.macro FCALL32 Selector, Offset
            .byte      0x09A
            .long      \Offset          # 32-bit offset
            .word      \Selector        # 16-bit selector
.endm

#-------------------------------------------------------------------------------------
#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.
#-------------------------------------------------------------------------------------
#RendezvousFunnelProc (&WakeUpBuffer,MemAddress)

ASM_GLOBAL ASM_PFX(RendezvousFunnelProc)
ASM_PFX(RendezvousFunnelProc):
RendezvousFunnelProcStart:

# At this point CS = 0x(vv00) and ip= 0x0.

        .byte 0x66,0x8b,0xe8          # mov        ebp, eax

        .byte 0x8c,0xc8               # mov        ax,  cs
        .byte 0x8e,0xd8               # mov        ds,  ax
        .byte 0x8e,0xc0               # mov        es,  ax
        .byte 0x8e,0xd0               # mov        ss,  ax
        .byte 0x33,0xc0               # xor        ax,  ax
        .byte 0x8e,0xe0               # mov        fs,  ax
        .byte 0x8e,0xe8               # mov        gs,  ax

# Get APIC ID
#
        .byte 0x66,  0xB8
        .long 0x00000001                 # mov        %eax, 1
        .byte 0x0F,  0xA2                # cpuid
        .byte 0x66,  0xC1, 0xEB, 0x18    # shr        %ebx, 24
        .byte 0x66,  0x81, 0xE3
        .long 0x000000FF                 # and        %ebx, 0ffh                   # EBX is keeping APIC ID

# If it is the first time AP wakes up, just record AP's BIST
# Otherwise, switch to flat mode

        .byte 0xBE, 0x24, 0x0C           # mov        si,  InitFlag
        .byte 0x66, 0x83, 0x3C, 0x01     # cmp        dword ptr [si], 1
        .byte 0x75, 0x18                 # jnz        flat32Start

# Record BIST information
#
        .byte 0xB0, 0x08                 # mov        al,  8
        .byte 0xF6, 0xE3                 # mul        bl

        .byte 0xBE, 0x2C,  0x0C          # mov        si,  BistBuffer
        .byte 0x03, 0xF0                 # add        si,  ax

        .byte 0x66, 0xC7, 0x04
        .byte 0x00000001                 # mov        dword ptr [si], 1           # Set Valid Flag
        .byte 0x66, 0x89, 0x6C, 0x04     # mov        dword ptr [si + 4], ebp     # Store BIST value

        cli
        hlt
        jmp .-2

# Switch to flat mode.

flat32Start:

        .byte 0xBE, 0x1C, 0x0C           # mov        si, BufferStart
        .byte 0x66, 0x8B, 0x0C           # mov        ecx,dword ptr [si]          # ECX is keeping the start address of wakeup buffer

        .byte 0xFA                       # cli
        .byte 0xBE, 0x10, 0x0C           # mov        si, GdtrProfile
        .byte 0x66                       # db         66h
        .byte 0x2E, 0x0F, 0x01, 0x14     # lgdt       fword ptr cs:[si]

        .byte 0xBE, 0x16, 0x0C           # mov        si, IdtrProfile
        .byte 0x66                       # db         66h
        .byte 0x2E, 0x0F, 0x01, 0x1C     # lidt       fword ptr cs:[si]


        .byte 0x33, 0xC0                 # xor        ax,  ax
        .byte 0x8E, 0xD8                 # mov        ds,  ax
        .byte 0x0F, 0x20, 0xC0           # mov        eax, cr0                    # Get control register 0
        .byte 0x66, 0x83, 0xC8, 0x01     # or         eax, 000000001h             # Set PE bit (bit #0)
        .byte 0x0F, 0x22, 0xC0           # mov        cr0, eax


#step-4:

FLAT32_JUMP:
        FJMP32  0x010, 0x0               # Far jmp using code segment descriptor

PMODE_ENTRY:                             # protected mode entry point

        movw        $0x8,%ax
        movw        %ax,%ds
        movw        %ax,%es
        movw        %ax,%fs
        movw        %ax,%gs
        movw        %ax,%ss              # Flat mode setup.

        movl        %ecx,%esi

        movl        %esi,%edi
        addl        $InitFlag, %edi
        cmpl        $2, (%edi)           # Check whether in S3 boot path
        jz          ProgramDynamicStack

ProgramStaticStack:

        xorl        %ecx, %ecx
        movl        %esi, %edi
        addl        $BistBuffer, %edi
        movl        (%edi, %ebx, 8), %ecx             # EBX = CpuNumber

        movl        %esi, %edi
        addl        $StackSize, %edi
        movl        (%edi), %eax
        incl        %ecx
        mull        %ecx                              # EAX = StackSize * (CpuNumber + 1)

        movl        %esi, %edi
        addl        $StackStart, %edi
        movl        (%edi), %edx
        addl        %edx, %eax                        # EAX = StackStart + StackSize * (CpuNumber + 1)

        movl        %eax, %esp
        subl        $MonitorFilterSize, %esp          # Reserved Monitor data space
        orl         $StartupApSignal, %ebx            # EBX = #Cpu run signature
        jmp         ProgramLocalApic

ProgramDynamicStack:

        movl        %esi, %edi
        addl        $LockLocation, %edi
        movb        $NotVacantFlag, %al
TestLock:
        xchgb       %al, (%edi)
        cmpb        $NotVacantFlag, %al
        jz          TestLock

        movl        %esi, %edi
        addl        $StackSize, %edi
        movl        (%edi), %eax
        movl        %esi, %edi
        addl        $StackStart, %edi
        addl        (%edi), %eax
        movl        %eax, %esp
        movl        %eax, (%edi)

Releaselock:
        movb        $VacantFlag, %al
        movl        %esi, %edi
        addl        $LockLocation, %edi
        xchgb       %al, (%edi)

ProgramLocalApic:

        movl        $0x0FEE000F0, %edi
        movl        (%edi), %eax
        andl        $0x0FFFFFD0F, %eax
        orl         $0x10F, %eax
        movl        %eax, (%edi)

        movl        $0x0FEE00350, %edi
        movl        (%edi), %eax
        andl        $0x0FFFE00FF, %eax
        orl         $0x700, %eax
        movl        %eax, (%edi)

        movl        $0x0FEE00360, %edi
        movl        (%edi), %eax
        andl        $0x0FFFE00FF, %eax
        orl         $0x10400, %eax
        movl        %eax, (%edi)
EnableXmm:
        movl        $1, %eax
        cpuid
        btl         $0x1A, %edx
        jnc         L1
        #
        # Enable XMM
        #
        movl %cr0, %eax
        orl  $2, %eax
        movl %eax, %cr0
        movl %cr4, %eax
        orl  $0x600, %eax
        movl %eax, %cr4

L1:
        #
        # Call C Function
        #
        movl         %esi, %edi
        addl         $RendezvousProc, %edi
        addl         $WakeUpApManner, %esi                # esi = WakeUpApManner Address Location

WakeUpThisAp:

        movl         (%edi), %eax

        testl        %eax, %eax
        jz          CheckWakeUpCounterInit

        push        %ebx
        push        %ebx
        push        %esi
        push        %edi

        subl        $0x20, %esp
        call        *%eax                           # Call C function
        addl        $0x20, %esp

        pop         %edi
        pop         %esi
        pop         %ebx
        pop         %ebx

CheckWakeUpCounterInit:
        cmpl        $ApCounterInit, (%esi)
        jnz         CheckWakeUpManner

#
# Initi%alize MONITOR_MWAIT_DATA data structure per thread
#
        xorl        %ecx, %ecx
        movl        %ecx, 0(%esp)         # BreakToRunApSignal
        movl        %ecx, 4(%esp)         # HltLoopBreakCounter
        movl        %ecx, 8(%esp)         # MwaitLoopBreakCounter
        movl        %ecx, 12(%esp)        # RunLoopBreakCounter
        movl        %ecx, 16(%esp)        # WakeUpApVectorChangeFlag
        movl        %ecx, 20(%esp)        # MwaitTargetCstate

CheckWakeUpManner:

        cmpl        $ApInHltLoop, (%esi)
        jz          HltApLoop

        cmpl        $ApInMwaitLoop, (%esi)
        jnz         CheckRunSignal

ApMwaitLoop:

        cli
        movl        %esp, %eax            # Set Monitor Address
        xorl        %ecx, %ecx
        xorl        %edx, %edx
        .byte       0x0f, 0x1, 0xc8       # MONITOR
        movl        20(%esp), %eax        # Mwait Target C-State per rax[7:4]
        .byte       0x0f, 0x1, 0xc9       # MWAIT

CheckRunSignal:

        cmpl        %ebx, (%esp)          # Check if run sign%al correct?
        jnz         CheckWakeUpManner     # Unknown break, go checking run manner

        jmp         WakeUpThisAp          # Jmp to execute AP task

HltApLoop:

        cli
        hlt
        jmp         HltApLoop

#RendezvousFunnelProc   ENDP
RendezvousFunnelProcEnd:

#-------------------------------------------------------------------------------------
#  AsmGetAddressMap (&AddressMap)
#-------------------------------------------------------------------------------------
ASM_GLOBAL ASM_PFX(AsmGetAddressMap)
ASM_PFX(AsmGetAddressMap):
        pushal
        movl         %esp, %ebp

        movl         0x24(%ebp), %ebx
        movl         $RendezvousFunnelProcStart, (%ebx)
        movl         $(PMODE_ENTRY - RendezvousFunnelProcStart), 0x4(%ebx)
        movl         $(FLAT32_JUMP - RendezvousFunnelProcStart), 0x8(%ebx)
        movl         $(RendezvousFunnelProcEnd - RendezvousFunnelProcStart), 0xc(%ebx)

        popal
        ret
#AsmGetAddressMap   ENDP

#-------------------------------------------------------------------------------------
#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)#
#-------------------------------------------------------------------------------------
.equ    CPU_SWITCH_STATE_IDLE,          0
.equ    CPU_SWITCH_STATE_STORED,        1
.equ    CPU_SWITCH_STATE_LOADED,        2

ASM_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 functiosn, stack will be corrupted.
        pushal
        movl         %esp, %ebp

        # %esi contains MyInfo pointer
        movl         0x24(%ebp), %esi

        # %edi contains OthersInfo pointer
        movl         0x28(%ebp), %edi

        #Store EFLAGS, GDTR and IDTR regiter to stack
        pushfl
        sgdt        8(%esi)
        sidt        14(%esi)

        # Store the its StackPointer
        movl        %esp, 4(%esi)

        # update its switch state to STORED
        movb        $NotVacantFlag, %al
TryLock1:
        lock xchgb  (%esi), %al
        cmpb        $VacantFlag, %al
        jz          LockObtained1
        PAUSE32
        jmp         TryLock1

LockObtained1:
        movb        $CPU_SWITCH_STATE_STORED, 1(%esi)
        lock xchgb  (%esi), %al
WaitForOtherStored:
        # wait until the other CPU finish storing its state
        movb        $NotVacantFlag, %al
TryLock2:
        lock xchgb  (%edi), %al
        cmpb        $VacantFlag, %al
        jz          LockObtained2
        PAUSE32
        jmp         TryLock2

LockObtained2:
        movb        1(%edi), %bl
        lock xchgb  (%edi),  %al
        cmpb        $CPU_SWITCH_STATE_STORED, %bl
        jb          WaitForOtherStored

        # Since another CPU already stored its state, load them
        # load GDTR value
        lgdt        8(%edi)

        # load IDTR value
        lidt        14(%edi)

        # load its future StackPointer
        movl        4(%edi), %esp

        # update its switch state to LOADED
        movb        $NotVacantFlag, %al
TryLock3:
        lock xchgb  (%esi), %al
        cmpb        $VacantFlag, %al
        jz          LockObtained3
        PAUSE32
        jmp         TryLock3

LockObtained3:
        movb        $CPU_SWITCH_STATE_LOADED, 1(%esi)
        lock xchgb  (%esi), %al

WaitForOtherLoaded:
        # wait until the other CPU finish loading new state,
        # otherwise the data in stack may corrupt
        movb        $NotVacantFlag, %al
TryLock4:
        lock xchgb  (%edi), %al
        cmpb        $VacantFlag, %al
        jz          LockObtained4
        PAUSE32
        jmp         TryLock4

LockObtained4:
        movb        1(%edi), %bl
        lock xchgb  (%edi), %al
        cmpb        $CPU_SWITCH_STATE_LOADED, %bl
        jb          WaitForOtherLoaded

        # since the other CPU already get the data it want, leave this procedure
        popfl

        popal
        ret
#AsmExchangeRole   ENDP