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
|
;------------------------------------------------------------------------------ ;
; Copyright (c) 2025, Intel Corporation. All rights reserved.<BR>
; SPDX-License-Identifier: BSD-2-Clause-Patent
;
; Module Name:
;
; ApRunLoop.nasm
;
; Abstract:
;
; This is the assembly code for run loop for APs in the guest TD
;
;-------------------------------------------------------------------------------
%include "TdxCommondefs.inc"
DEFAULT REL
SECTION .bss
global STACK_BASE
STACK_BASE:
resb 1024
STACK_TOP:
SECTION .text
%define TDX_WORK_AREA_MAILBOX_GDTR (FixedPcdGet32 (PcdOvmfWorkAreaBase) + 128)
%define PT_ADDR(Offset) (FixedPcdGet32 (PcdOvmfSecPageTablesBase) + (Offset))
%define TDX_WORK_AREA_PGTBL_READY (FixedPcdGet32 (PcdOvmfWorkAreaBase) + 4)
%define PG_5_LEVEL (FixedPcdGetBool (PcdUse5LevelPageTable))
%define TDX_BSP 1
%define TDX_AP 2
%define TDX_AP_5_LEVEL 3
BITS 64
%define TDVMCALL_EXPOSE_REGS_MASK 0xffc4
%define TDVMCALL 0x0
%define EXIT_REASON_CPUID 0xa
; Defined in ACPI 6.6 section 5.2.12.19 MultiProcessor Wakeup Mailbox Command.
%define MULTIPROCESSOR_WAKEUP_MAILBOX_COMMAND_NOOP 0
%define MULTIPROCESSOR_WAKEUP_MAILBOX_COMMAND_WAKEUP 1
%define MULTIPROCESSOR_WAKEUP_MAILBOX_COMMAND_TEST 2
%macro tdcall 0
db 0x66, 0x0f, 0x01, 0xcc
%endmacro
%macro tdcall_regs_preamble 2
mov rax, %1
xor rcx, rcx
mov ecx, %2
; R10 = 0 (standard TDVMCALL)
xor r10d, r10d
; Zero out unused (for standard TDVMCALL) registers to avoid leaking
; secrets to the VMM.
xor esi, esi
xor edi, edi
xor edx, edx
xor ebp, ebp
xor r8d, r8d
xor r9d, r9d
xor r14, r14
xor r15, r15
%endmacro
;
; Relocated Ap Mailbox loop
;
; @param[in] RBX: Relocated mailbox address
; @param[in] RBP: vCpuId
;
; @return None This routine does not return
;
global ASM_PFX(AsmRelocateApMailBoxLoop)
ASM_PFX(AsmRelocateApMailBoxLoop):
AsmRelocateApMailBoxLoopStart:
mov r11, EXIT_REASON_CPUID
mov r12, 0xb
tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK
tdcall
test r10, r10
jnz Panic
mov r8, r15
mov qword[rel mailbox_address], rbx
MailBoxLoop:
; Spin until command set
cmp dword [rbx + CommandOffset], MULTIPROCESSOR_WAKEUP_MAILBOX_COMMAND_NOOP
je MailBoxLoop
; Determine if this is a broadcast or directly for my apic-id, if not, ignore
cmp dword [rbx + ApicidOffset], MailboxApicidBroadcast
je MailBoxProcessCommand
cmp dword [rbx + ApicidOffset], r8d
jne MailBoxLoop
MailBoxProcessCommand:
cmp dword [rbx + CommandOffset], MULTIPROCESSOR_WAKEUP_MAILBOX_COMMAND_WAKEUP
je MailBoxWakeUp
cmp dword [rbx + CommandOffset], MULTIPROCESSOR_WAKEUP_MAILBOX_COMMAND_TEST
je MailBoxTest
; Don't support this command, so ignore
jmp MailBoxLoop
MailBoxWakeUp:
mov rax, [rbx + WakeupVectorOffset]
; OS sends a wakeup command for a given APIC ID, firmware is supposed to reset
; the command field back to zero as acknowledgement.
mov qword [rbx + CommandOffset], 0
jmp rax
MailBoxTest:
mov qword [rbx + CommandOffset], 0
jmp MailBoxLoop
Panic:
ud2
AsmRelocateApResetVector:
.prepareStack:
; The stack can then be used to switch from long mode to compatibility mode
mov rsp, STACK_TOP
.loadGDT:
cli
mov rax, TDX_WORK_AREA_MAILBOX_GDTR
lgdt [rax]
.loadSwicthModeCode:
mov rcx, dword 0x10 ; load long mode selector
shl rcx, 32
lea rdx, [LongMode] ; assume address < 4G
or rcx, rdx
push rcx
mov rcx, dword 0x08 ; load compatible mode selector
shl rcx, 32
lea rdx, [Compatible] ; assume address < 4G
or rcx, rdx
push rcx
retf
BITS 32
Compatible:
mov eax, dword 0x18
; ; reload DS/ES/SS to make sure they are correct referred to current GDT
mov ds, ax
mov es, ax
mov ss, ax
; reload the fs and gs
mov fs, ax
mov gs, ax
; Must clear the CR4.PCIDE before clearing paging
mov ecx, cr4
btc ecx, 17
mov cr4, ecx
;
; Disable paging
;
mov ecx, cr0
btc ecx, 31
mov cr0, ecx
;
RestoreCr0:
; Only enable PE(bit 0), NE(bit 5), ET(bit 4) 0x31
mov eax, dword 0x31
mov cr0, eax
; Only Enable MCE(bit 6), VMXE(bit 13) 0x2040
; TDX enforeced the VMXE = 1 and mask it in VMM, so not set it.
RestoreCr4:
mov eax, 0x40
mov cr4, eax
%if PG_5_LEVEL
mov al, byte[TDX_WORK_AREA_PGTBL_READY]
inc eax
cmp eax, TDX_AP_5_LEVEL
jne SetCr3
SetCr4La57:
; set la57 bit in cr4
mov eax, cr4
bts eax, 12
mov cr4, eax
%endif
SetCr3:
;
; Can use the boot page tables since it's reserved
mov eax, PT_ADDR (0)
mov cr3, eax
EnablePAE:
mov eax, cr4
bts eax, 5
mov cr4, eax
EnablePaging:
mov eax, cr0
bts eax, 31 ; set PG
mov cr0, eax ; enable paging
; return to LongMode
retf
BITS 64
LongMode:
mov rbx, qword[rel mailbox_address]
jmp AsmRelocateApMailBoxLoopStart
align 16
mailbox_address:
dq 0
BITS 64
AsmRelocateApMailBoxLoopEnd:
;-------------------------------------------------------------------------------------
; AsmGetRelocationMap (&RelocationMap);
;-------------------------------------------------------------------------------------
global ASM_PFX(AsmGetRelocationMap)
ASM_PFX(AsmGetRelocationMap):
; mov byte[TDX_WORK_AREA_MB_PGTBL_READY], 0
lea rax, [AsmRelocateApMailBoxLoopStart]
mov qword [rcx], rax
mov qword [rcx + 8h], AsmRelocateApMailBoxLoopEnd - AsmRelocateApMailBoxLoopStart
lea rax, [AsmRelocateApResetVector]
mov qword [rcx + 10h], rax
ret
|