1;------------------------------------------------------------------------------ ;
2; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
3; This program and the accompanying materials
4; are licensed and made available under the terms and conditions of the BSD License
5; which accompanies this distribution.  The full text of the license may be found at
6; http://opensource.org/licenses/bsd-license.php.
7;
8; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10;
11; Module Name:
12;
13;   MpFuncs32.asm
14;
15; Abstract:
16;
17;   This is the assembly code for MP support
18;
19;-------------------------------------------------------------------------------
20
21include  MpEqu.inc
22extern   InitializeFloatingPointUnits:PROC
23
24.code
25;-------------------------------------------------------------------------------------
26;RendezvousFunnelProc  procedure follows. All APs execute their procedure. This
27;procedure serializes all the AP processors through an Init sequence. It must be
28;noted that APs arrive here very raw...ie: real mode, no stack.
29;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
30;IS IN MACHINE CODE.
31;-------------------------------------------------------------------------------------
32RendezvousFunnelProc   PROC  PUBLIC
33RendezvousFunnelProcStart::
34; At this point CS = 0x(vv00) and ip= 0x0.
35; Save BIST information to ebp firstly
36    db 66h,  08bh, 0e8h               ; mov        ebp, eax    ; save BIST information
37
38    db 8ch,0c8h                       ; mov        ax,cs
39    db 8eh,0d8h                       ; mov        ds,ax
40    db 8eh,0c0h                       ; mov        es,ax
41    db 8eh,0d0h                       ; mov        ss,ax
42    db 33h,0c0h                       ; xor        ax,ax
43    db 8eh,0e0h                       ; mov        fs,ax
44    db 8eh,0e8h                       ; mov        gs,ax
45
46    db 0BEh                           ; opcode of mov si, mem16
47    dw BufferStartLocation            ; mov        si, BufferStartLocation
48    db 66h,  8Bh, 1Ch                 ; mov        ebx,dword ptr [si]
49
50    db 0BFh                           ; opcode of mov di, mem16
51    dw PmodeOffsetLocation            ; mov        di, PmodeOffsetLocation
52    db 66h,  8Bh, 05h                 ; mov        eax,dword ptr [di]
53    db 8Bh,  0F8h                     ; mov        di, ax
54    db 83h,  0EFh,06h                 ; sub        di, 06h
55    db 66h,  03h, 0C3h                ; add        eax, ebx
56    db 66h,  89h, 05h                 ; mov        dword ptr [di],eax
57
58    db 0BFh                           ; opcode of mov di, mem16
59    dw LmodeOffsetLocation            ; mov        di, LmodeOffsetLocation
60    db 66h,  8Bh, 05h                 ; mov        eax,dword ptr [di]
61    db 8Bh,  0F8h                     ; mov        di, ax
62    db 83h,  0EFh,06h                 ; sub        di, 06h
63    db 66h,  03h, 0C3h                ; add        eax, ebx
64    db 66h,  89h, 05h                 ; mov        dword ptr [di],eax
65
66    db 0BEh
67    dw Cr3Location                    ; mov        si, Cr3Location
68    db 66h,  8Bh, 0Ch                 ; mov        ecx,dword ptr [si]     ; ECX is keeping the value of CR3
69
70    db 0BEh                           ; opcode of mov si, mem16
71    dw GdtrLocation                   ; mov        si, GdtrLocation
72    db 66h                            ; db         66h
73    db 2Eh,  0Fh, 01h, 14h            ; lgdt       fword ptr cs:[si]
74
75    db 0BEh
76    dw IdtrLocation                   ; mov        si, IdtrLocation
77    db 66h                            ; db         66h
78    db 2Eh,0Fh, 01h, 1Ch              ; lidt       fword ptr cs:[si]
79
80    db 33h,  0C0h                     ; xor        ax,  ax
81    db 8Eh,  0D8h                     ; mov        ds,  ax
82
83    db 0Fh,  20h, 0C0h                ; mov        eax, cr0               ;Get control register 0
84    db 66h,  83h, 0C8h, 03h           ; or         eax, 000000003h        ;Set PE bit (bit #0) & MP
85    db 0Fh,  22h, 0C0h                ; mov        cr0, eax
86
87    db 66h,  67h, 0EAh                ; far jump
88    dd 0h                             ; 32-bit offset
89    dw PROTECT_MODE_CS                ; 16-bit selector
90
91Flat32Start::                         ; protected mode entry point
92    mov        ax, PROTECT_MODE_DS
93    mov        ds, ax
94    mov        es, ax
95    mov        fs, ax
96    mov        gs, ax
97    mov        ss, ax
98
99    db 0Fh,  20h,  0E0h           ; mov        eax, cr4
100    db 0Fh,  0BAh, 0E8h, 05h      ; bts        eax, 5
101    db 0Fh,  22h,  0E0h           ; mov        cr4, eax
102
103    db 0Fh,  22h,  0D9h           ; mov        cr3, ecx
104
105    db 0B9h
106    dd 0C0000080h                 ; mov        ecx, 0c0000080h     ; EFER MSR number.
107    db 0Fh,  32h                  ; rdmsr                          ; Read EFER.
108    db 0Fh,  0BAh, 0E8h, 08h      ; bts        eax, 8              ; Set LME=1.
109    db 0Fh,  30h                  ; wrmsr                          ; Write EFER.
110
111    db 0Fh,  20h,  0C0h           ; mov        eax, cr0            ; Read CR0.
112    db 0Fh,  0BAh, 0E8h, 1Fh      ; bts        eax, 31             ; Set PG=1.
113    db 0Fh,  22h,  0C0h           ; mov        cr0, eax            ; Write CR0.
114
115LONG_JUMP:
116    db 67h,  0EAh                 ; far jump
117    dd 0h                         ; 32-bit offset
118    dw LONG_MODE_CS               ; 16-bit selector
119
120LongModeStart::
121    mov        ax,  LONG_MODE_DS
122    mov        ds,  ax
123    mov        es,  ax
124    mov        ss,  ax
125
126    mov        esi, ebx
127    mov        edi, esi
128    add        edi, LockLocation
129    mov        rax, NotVacantFlag
130
131TestLock:
132    xchg       qword ptr [edi], rax
133    cmp        rax, NotVacantFlag
134    jz         TestLock
135
136    mov        edi, esi
137    add        edi, NumApsExecutingLoction
138    inc        dword ptr [edi]
139    mov        ebx, dword ptr [edi]
140
141ProgramStack:
142    mov        edi, esi
143    add        edi, StackSizeLocation
144    mov        rax, qword ptr [edi]
145    mov        edi, esi
146    add        edi, StackStartAddressLocation
147    add        rax, qword ptr [edi]
148    mov        rsp, rax
149    mov        qword ptr [edi], rax
150
151Releaselock:
152    mov        rax, VacantFlag
153    mov        edi, esi
154    add        edi, LockLocation
155    xchg       qword ptr [edi], rax
156
157CProcedureInvoke:
158    push       rbp               ; push BIST data
159    xor        rbp, rbp          ; clear ebp for call stack trace
160    push       rbp
161    mov        rbp, rsp
162
163    mov        rax, InitializeFloatingPointUnits
164    sub        rsp, 20h
165    call       rax               ; Call assembly function to initialize FPU per UEFI spec
166    add        rsp, 20h
167
168    mov        edx, ebx          ; edx is NumApsExecuting
169    mov        ecx, esi
170    add        ecx, LockLocation ; rcx is address of exchange info data buffer
171
172    mov        edi, esi
173    add        edi, ApProcedureLocation
174    mov        rax, qword ptr [edi]
175
176    sub        rsp, 20h
177    call       rax               ; invoke C function
178    add        rsp, 20h
179    jmp        $
180
181RendezvousFunnelProc   ENDP
182RendezvousFunnelProcEnd::
183
184;-------------------------------------------------------------------------------------
185;  AsmGetAddressMap (&AddressMap);
186;-------------------------------------------------------------------------------------
187AsmGetAddressMap   PROC
188    mov        rax, offset RendezvousFunnelProcStart
189    mov        qword ptr [rcx], rax
190    mov        qword ptr [rcx +  8h], Flat32Start - RendezvousFunnelProcStart
191    mov        qword ptr [rcx + 10h], LongModeStart - RendezvousFunnelProcStart
192    mov        qword ptr [rcx + 18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
193    ret
194AsmGetAddressMap   ENDP
195
196;-------------------------------------------------------------------------------------
197;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
198;about to become an AP. It switches it'stack with the current AP.
199;AsmExchangeRole (IN   CPU_EXCHANGE_INFO    *MyInfo, IN   CPU_EXCHANGE_INFO    *OthersInfo);
200;-------------------------------------------------------------------------------------
201AsmExchangeRole   PROC
202    ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
203    ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
204
205    push       rax
206    push       rbx
207    push       rcx
208    push       rdx
209    push       rsi
210    push       rdi
211    push       rbp
212    push       r8
213    push       r9
214    push       r10
215    push       r11
216    push       r12
217    push       r13
218    push       r14
219    push       r15
220
221    mov        rax, cr0
222    push       rax
223
224    mov        rax, cr4
225    push       rax
226
227    ; rsi contains MyInfo pointer
228    mov        rsi, rcx
229
230    ; rdi contains OthersInfo pointer
231    mov        rdi, rdx
232
233    ;Store EFLAGS, GDTR and IDTR regiter to stack
234    pushfq
235    sgdt       fword ptr [rsi + 16]
236    sidt       fword ptr [rsi + 26]
237
238    ; Store the its StackPointer
239    mov        qword ptr [rsi + 8], rsp
240
241    ; update its switch state to STORED
242    mov        byte ptr [rsi], CPU_SWITCH_STATE_STORED
243
244WaitForOtherStored:
245    ; wait until the other CPU finish storing its state
246    cmp        byte ptr [rdi], CPU_SWITCH_STATE_STORED
247    jz         OtherStored
248    pause
249    jmp        WaitForOtherStored
250
251OtherStored:
252    ; Since another CPU already stored its state, load them
253    ; load GDTR value
254    lgdt       fword ptr [rdi + 16]
255
256    ; load IDTR value
257    lidt       fword ptr [rdi + 26]
258
259    ; load its future StackPointer
260    mov        rsp, qword ptr [rdi + 8]
261
262    ; update the other CPU's switch state to LOADED
263    mov        byte ptr [rdi], CPU_SWITCH_STATE_LOADED
264
265WaitForOtherLoaded:
266    ; wait until the other CPU finish loading new state,
267    ; otherwise the data in stack may corrupt
268    cmp        byte ptr [rsi], CPU_SWITCH_STATE_LOADED
269    jz         OtherLoaded
270    pause
271    jmp        WaitForOtherLoaded
272
273OtherLoaded:
274    ; since the other CPU already get the data it want, leave this procedure
275    popfq
276
277    pop        rax
278    mov        cr4, rax
279
280    pop        rax
281    mov        cr0, rax
282
283    pop        r15
284    pop        r14
285    pop        r13
286    pop        r12
287    pop        r11
288    pop        r10
289    pop        r9
290    pop        r8
291    pop        rbp
292    pop        rdi
293    pop        rsi
294    pop        rdx
295    pop        rcx
296    pop        rbx
297    pop        rax
298
299    ret
300AsmExchangeRole   ENDP
301
302AsmInitializeGdt   PROC
303    push       rbp
304    mov        rbp, rsp
305
306    lgdt       fword PTR [rcx]  ; update the GDTR
307
308    sub        rsp, 0x10
309    lea        rax, SetCodeSelectorFarJump
310    mov        [rsp], rax
311    mov        rdx, LONG_MODE_CS
312    mov        [rsp + 4], dx    ; get new CS
313    jmp        fword ptr [rsp]
314SetCodeSelectorFarJump:
315    add        rsp, 0x10
316
317    mov        rax, LONG_MODE_DS          ; get new DS
318    mov        ds, ax
319    mov        es, ax
320    mov        fs, ax
321    mov        gs, ax
322    mov        ss, ax
323
324    pop        rbp
325    ret
326AsmInitializeGdt  ENDP
327
328END
329