forked from jyao1/STM
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Readme.STMPE
378 lines (284 loc) · 17.1 KB
/
Readme.STMPE
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
STMPE Addtions to the STM API
AddPEVMtempVMCALL:
AddPEVMpermVMCALL:
Create a protected execution (PE) virtual machine (VM) and load a module to be executed
!in that VM.
AddPEVMtempVMCALL:
The module is temporarily loaded in a VM, executed, and the VM torn down afterwards. i.e.
protected execution.
Input and Return register values: same as AddPEVMpermVMCALL.
AddPEVMpermVMCALL:
The module is permanently loaded in a VM and persists. It is expected that this will be
allowed only when the MLE is initially brought up to allow for a measurement engine to be
loaded. This module is executed by the RunPeVmVMCALL.
Input registers:
EAX = STM_API_ADD_TEMP_PE or STM_API_ADD_PERM_PE_VM
EBX = low 32 bits of physical address of a caller created structure
containing module load information (struct module_info)
ECX = high 32 bits of physical address of a caller created structure
containing module load information (struct module_info)
Return register values:
CF = 0: No error, EAX set to STM_SUCCESS (0)
CF = 1: An error occurred, EAX holds relevant error value
EAX: Error/success return
RunPeVmVMCALL
This call runs the VM that was created via the AddSTMVmVMCALL vmcall. Entrypoint into the
module will be that defined during the AddSTMVmVMCALL.
Input registers:
EAX = RunPeVmVMCALL
Output registers:
CF = 0: No error, EAX set to STM_SUCCESS (0)
CF = 1: An error occurred, EAX holds relevant error value EAX = -1 (actual error values
TBD)
EndAddPeVmVMCALL
Turns off the ability to add a permanent PE VM. This function is normally
ran at the end of the MLE's processing to ensure that no permanent
untrusted entity resides in the STM.
Bit definitions for the additions to the STM API
STM_API_ADD_TEMP_PE_VM 0x00010009
STM_API_ADD_PERM_PE_VM 0x0001000a
STM_API_END_PERM_PE_VM 0x0001000c
STM_API_RUN_PERM_PE_VM 0x0001000b
STM_API_ADD_PERM_PE_VM_NORUN 0x0001000d
Information block used to pass information about the PE module to the STM:
struct module_info {
u64 module_address; - physical address of VM/PE (SMM) module to load
u64 module_load_address; - guest-physical load address of module (must be
- within the range of address_space_start and
- address_space_start+addresss_space_size)
u32 module_size; - size of module in bytes
u32 module_entry_point; - relative offset from start of module
u64 address_space_start; - guest-physical address space start of module
u32 address_space_size; - module size in bytes
u32 vmconfig; - flags specifying how VM supporting module should
- be configured (see below for definitions)
u64 cr3_load; - guest-physical address to initialize cr3 to if
- paging enabled
u64 shared_page; - guest-physical address of a shared page (must not
- be in SMRAM space). segment will have R/W
- permission. value placed in RBX register of STM
- module.
struct region *segment; - guest-physical address of an array of R/O
- segments terminated with a null element.
- value placed in RCX register of STM module.
u32 shared_page_size; - size of shared page
u32 DoNotClearSize; - block at beginning of data not to be cleared
u64 ModuleDataSection; - start address of the module data section
} __attribute__((__packed__));
vmconfig settings:
SET_CS_L (1<<13) - cs.l set 64bit mode for cs (req. SET_IA32E is set)
SET_CS_D (1<<14) - cs.d default mode (0: 16bit seg, 1: 32-bit)
must be set if SET_CS_L is set
SET_IA32E (1<<15) - sets IA32e mode; when set, cr0.pg, cr0.pe, and
cr0.pae will be set as well
SET_CR0_PG (1<<31) - set cr0.pg
SET_CR0_PE (1<<0) - set cr0.pe
SET_CR4_PAE (1<<3) - set cr4.pae
SET_PERM_VM (1<<2) - VM can be re-executed using
STM_API_RUN_VM(RunPeVmVMCALL)
SET_PERM_VM_RUN_ONCE (1<<20) - run perm VM only once, then breakdown
SET_PERM_VM_CRASH_BREAKDOWN (1<<21) - if Perm VM crashes, then breakdown
SET_PERM_VM_RUN_SMI (1<<22) - Run VM/PE via SMI timer (every 16 Seconds)
SET_VM_CLEAR_MEMORY (1<<23) - Clear heap before each run
SET_VM_TEXT_RW (1<<24) - set VM/PE text space as RW
SET_VM_EXEC_HEAP (1<<25) - allow execution in Heap Space
SET_PERM_VM_HANDLE_INT (1<<26) - allow perm VM/PE to handle internal interrupts
error returns - placed in eax upon return to caller:
PE_SUCCESS 0 - PE setup/ran sucessfully
PE_FAIL -1 - catchall PE ERROR
PE_SPACE_TOO_LARGE 0x80040001 - requested memory space too large
PE_MODULE_ADDRESS_TOO_LOW 0x80040002 - PE module start below address space start
PE_MODULE_TOO_LARGE 0x80040003 - PE module too large for address space
(or located such that it overflows
the end of the address space
PE_NO_PT_SPACE 0x80040004 - not enough space left for PE VM
page tables
PE_NO_RL_SPACE 0x80040005 - not enough space left for resource
list
PE_MEMORY_AC_SETUP_FAILURE 0x80040006 - could not setup accesses to PE space
(internal error)
PE_SHARED_MEMORY_SETUP_ERROR 0x80040007 - could not setup shared memory
PE_MODULE_MAP_FAILURE 0x80040008 - could not map in the address space
PE_SHARED_MAP_FAILURE 0x80040009 - could not map in the shared page
PE_VMCS_ALLOC_FAIL 0x8004000A - could not allocate VMCS memory
PE_VMLAUNCH_ERROR 0x8004000B - attempted to launch PE VM with bad
guest VM state
PE_VM_BAD_ACCESS 0x8004000C - PE VM attempted to access protected
memory out of bounds)
PE_VM_SETUP_ERROR_D_L 0x8004000D - CS_D and CS_L cannot be set to one at
the same time
PE_VM_SETUP_ERROR_IA32E_D 0x8004000E - SET_IA32E must be set when CS_L is
set
PE_VM_TRIPLE_FAULT 0x8004000F - PE VM crashed with a triple fault
PE_VM_PAGE_FAULT 0x80040010 - PE VM crashed with a page fault
Region list structure
struct region {
u64 address; - page aligned physical address
u32 size; - size of segment
u32 padding; - align structure to 64-bits
} __attribute__((__packed__));
STM/PE and VM/PE interaction
Note: The current VM/PE application is XHIM (Xen Integrity Monitory) and the interface is biased
towards supporting that application. The interface will be modified as other applications are
introduced for other VM/PE's.
When the XHIM VM/PE is started, the register contents are as follows:
RBX - Shared page (low)
RCX - Shared page (high)
RDX - Shared STM Page
Shared Page - (64 bit address) This is a region of memory that is located outside of
SMRAM. It is readable/writeable by the VM/PE application. Generally, used as an
output buffer for the VM/PE application.
Shared STM Page - This is a region shared between shared between the VM/PE application.
The VM/PE application has readonly access. This region begins at the top of the PE/VM
memory and is used, in the case of XHIM, to provide the processor state information.
VM/PE VMCALLS for XHIM
STM_API_MAP_ADDRESS_RANGE - Maps a non-SMRAM address range into the address space accessible
by the PE/VM. This address range is read-only for the VM/PE.
RBX - Address of parameter block (Upper)
RCX - Address of parameter block (Lower)
Format of parameter block:
u64 - Physical address to be mapped
u64 - Number of pages to be mapped
Status return
RFLAGS_CF = 0 success
RAX = STM_SUCCESS
RFLAGS_CF = 1 fail
RAX = ERROR_STM_CACHE_TYPE_NOT_SUPPORTED
ERROR_STM_PAGE_NOT_FOUND
ERROR_STM_SECURITY_VIOLATION
STM_API_GET_VMCS_MAP - Provides the VMCS map. The VMCS map is created when the VM/PE is initially
setup. It is a mapping between the relative VMCS location and the associated VMCS data field.
Caution must be exercised when using this mapping as the x86 processors cache the VMCS and in-
memory values may be stale as the current value may be in the processor cache.
RBX - Address for VMCS map (Upper)
RCX - Address for VMCS map (Lower)
One page should be allocated for this map to prevent overrun of
the VM/PE memory.
Use the VMCS field encoding as an index into a 16-bit array, where
each array element holds the offset of the data in the VMCS.
Note: this data may become stale due to processor caching.
Status return
RFLAGS_CF = 0 success
RAX = STM_SUCCESS
RFLAGS_CF = 1 fail
RAX = ERROR_STM_CACHE_TYPE_NOT_SUPPORTED
ERROR_STM_PAGE_NOT_FOUND
ERROR_STM_SECURITY_VIOLATION
END VMCALLS
Processor state information provided by the STM for each XHIM run.
When a VMEXIT occurs, each processor's state information is contained within the guest portion of
the SMM-transfer VMCS. The SMM-transfer VMCS is created during the STM initial startup and is the
current VMCS when the STM gains control after the VMEXIT into SMM. There is one per processor and
is contained within the STM's address space. The STM extracts this state information and places it
into the STM shared page for XHIM to access.
When an SMM VMEXIT occurs, the processor is in either non-root operation or in root operation.
This operational mode determines how the executive-VMCS pointer field is set. If the VMM was in
non-root operation the current-VMCS pointer is placed into the executive-VMCS field. Otherwise if
the VMM is in root operation the VMXON pointer is placed there.
The STM uses these values to determine if each operational mode of each processor. And this result
is placed into the VmxState field of the ROOT_VMX_STATE data structure for each processor, which
has two possible values: VMX_STATE_ROOT (1) and VMX_STATE_GUEST (2).
There is an additional calculation that STM does based on the VMCS link pointer, which sets the
VmcsType field. When VmState is VMX_STATE_ROOT, the VmcsType is 1 when there is no link VMCS and 2
when there is a link VMCS. This represents the current VMCS, which that processor may soon do a
vmlaunch (or vmresume).
VmcsType equal to 3 represents VmxState as VMX_STATE_GUEST that has been interrupted. Note: the
VMCS link field for this VmcsType may have some application for nested virtualization, but is not
calculated. The VMCS link field is provided as LinkVMCS.
Finding the Xen CR3 for each processor.
For processors that are in VMX_STATE_ROOT the guest CR3 should have the proper value. However,
this gets complicated by the possibility a processor can be executing either a para-virtualized
(PV) machine or is running idle or managing a guest virtual machine. The idle case would have an
idle page table associated with it. Each PV would also have an unique page table associated with
it. However, there should be a 64MB region of the PV address space that is linked into Xen's
address space. Note: the protection of this space should checked.
For processors that are in VMX_STATE_GUEST, the Xen CR3 is found in the host CR3 as the guest CR3
is local to the virtual machine's address space.
Note: Ihost values may be be present in the VMX_STATE_ROOT data structures. Don't use these values
as they seem to be residue values when the processor was in VMX_STATE_GUEST. They are meaningless
in root operation.
Example of VMX_STATE_GUEST/VmcsType=3
Note: the (3) is the VmcsType. When the type is 3, H_CR3 is the Xen CR3 (actually idle_pg_table).
(STM) 9 PrintVmxState (3): execVMCS is guest VMCS: 0x000000102FEB3000 using Executive VMCS
(STM) 9 PrintVmxState (3) HostRootVmcs 0x000000102FEB3000
G_CR0 80050033
G_CR3 7CEE6000
G_CR4 3626F0
G_GDTR FFFF9E7A4940C000:7F
G_IDTR FFFFFFFFFF528000:FFFFFFFF
G_RSP FFFF9E79BDB2F5C8
G_RIP FFFFFFFFA4B9E8F5
VMXON 10493F0000
ExecutiveVMCS 102FEB3000
LinkVMCS FFFFFFFFFFFFFFFF
H_CR0 80050033
H_CR3 102FFCA000
H_CR4 3526E0
H_GDTR FFFF8310755F3000
H_IDTR FFFF8310493F7000
H_RSP FFFF8310493FFF70
H_RIP FFFF82D08031A1D0
H_EPT 102FFF801E
This next example is of VMX_STATE_ROOT and note that the VmcsType=1. This is also the processor
that XHIM is running on. XHIM will always execute on the same processor. This is done in order to
get away from some OS issues with a processor disappearing during extended SMM, so that the
processor has to be "unplugged." Normally, under Xen this is processor #1. However, when there are
a lot of processors like on a 16 processor server, that selection is not an invariant and any
processor except for processor 0 can be used. So, to use the XHIM processor values, XHIM needs to
figure out which processor it is on or the STM can provide the processor number when the STM
passes the processor state information to XHIM.
(STM) 1 PrintVmxState (1): execVMCS is vmxon: 0x0000001075605000 using VMCS_LINK_POINTER
(STM) 1 PrintVmxState (1) HostRootVmcs 0x0000001075605000
G_CR0 8005003B
G_CR3 7DA4A000
G_CR4 3526E0
G_GDTR FFFF8310755FF000:EFFF
G_IDTR FFFF83107560B000:FFFFFFFF
G_RSP FFFF831075617EA8
G_RIP FFFF82D0802CE6E8
VMXON 1075606000
ExecutiveVMCS 1075606000
LinkVMCS 1075605000
H_CR0 0
H_CR3 0
H_CR4 0
H_GDTR 0
H_IDTR 0
H_RSP 0
H_RIP 0
H_EPT 0
Notes:
Interrupts and faults:
The VM/PE module can be configured at setup time to have the STM inject faults. In this case,
the VM/PE module must setup an IDT along with the necessary fault handlers. Otherwise, the STM
will detect the lack of an IDT and abort the VM/PE when a fault occurs. Also, when STM is not
configured to inject faults, the VM/PE will be terminated when a fault occurs.
The VM/PE will not receive external interrupts.
Memory allocation errors:
Allocation errors for the PE module most likely mean that there is not enough
contiguous memory to fit the PE module in. The memory allocation could be
modified to allocate memory in smaller blocks from the STM heap, but as more
pages are allocated, the higher the overhead necessary for page tables.
Memory allocation errors for the overhead really mean that you should consider
reducing the size of the PE module. As at this point heap memory may
be getting so limited as the affect the operation of the STM itself.
To prevent this, the size of the PE module should be limited to
ensure that there is enough heap space for the STM to function.
MSR and I/O access:
Read and write access to the IA32_EFER_MSR is allowed, write access
to other MSRs are ignored and read attempts to other MSRs will return 0.
IO ports:
Access attempts to I/O ports are ignored except for 0x3D8 and 0x3F8.
0x3D8 and 0x3F8 (aka COM2 and COM1 respectively) can be used to send character
strings through the STM console port.
No formatting, etc is done (any byte combinations that can pose a security
issue will be delt with as necessary). However, the STM will prefix each line with a '(VM/PE)'
and route the character string to either/both a configured serial port and to the coreboot
CBMEM console.
for debugging a VM/PE debugging output can be sent through:
RDX: port - 0x3F8 or 0x3D8
RCX: number of bytes (maximun length is 200. Stings longer than that
will be truncated)
DS:ESI location in PE/VM where output is located
Use either instruction OUTSB/OUTSW/OUTSD (0x6E or Ox6F)
Note: do not use a loop with a rep statement (which is what is normally done)