VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/VMMR0JmpA-x86.asm@ 100266

Last change on this file since 100266 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.8 KB
Line 
1; $Id: VMMR0JmpA-x86.asm 98103 2023-01-17 14:15:46Z vboxsync $
2;; @file
3; VMM - R0 SetJmp / LongJmp routines for X86.
4;
5
6;
7; Copyright (C) 2006-2023 Oracle and/or its affiliates.
8;
9; This file is part of VirtualBox base platform packages, as
10; available from https://www.virtualbox.org.
11;
12; This program is free software; you can redistribute it and/or
13; modify it under the terms of the GNU General Public License
14; as published by the Free Software Foundation, in version 3 of the
15; License.
16;
17; This program is distributed in the hope that it will be useful, but
18; WITHOUT ANY WARRANTY; without even the implied warranty of
19; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20; General Public License for more details.
21;
22; You should have received a copy of the GNU General Public License
23; along with this program; if not, see <https://www.gnu.org/licenses>.
24;
25; SPDX-License-Identifier: GPL-3.0-only
26;
27
28;*******************************************************************************
29;* Header Files *
30;*******************************************************************************
31%include "VBox/asmdefs.mac"
32%include "VMMInternal.mac"
33%include "VBox/err.mac"
34%include "VBox/param.mac"
35
36
37;*******************************************************************************
38;* Defined Constants And Macros *
39;*******************************************************************************
40%define RESUME_MAGIC 07eadf00dh
41%define STACK_PADDING 0eeeeeeeeh
42
43
44
45BEGINCODE
46
47
48;;
49; The setjmp variant used for calling Ring-3.
50;
51; This differs from the normal setjmp in that it will resume VMMRZCallRing3 if we're
52; in the middle of a ring-3 call. Another differences is the function pointer and
53; argument. This has to do with resuming code and the stack frame of the caller.
54;
55; @returns VINF_SUCCESS on success or whatever is passed to vmmR0CallRing3LongJmp.
56; @param pJmpBuf msc:rcx gcc:rdi x86:[esp+0x04] Our jmp_buf.
57; @param pfn msc:rdx gcc:rsi x86:[esp+0x08] The function to be called when not resuming.
58; @param pvUser1 msc:r8 gcc:rdx x86:[esp+0x0c] The argument of that function.
59; @param pvUser2 msc:r9 gcc:rcx x86:[esp+0x10] The argument of that function.
60;
61BEGINPROC vmmR0CallRing3SetJmp
62GLOBALNAME vmmR0CallRing3SetJmp2
63GLOBALNAME vmmR0CallRing3SetJmpEx
64 ;
65 ; Save the registers.
66 ;
67 mov edx, [esp + 4h] ; pJmpBuf
68 mov [xDX + VMMR0JMPBUF.ebx], ebx
69 mov [xDX + VMMR0JMPBUF.esi], esi
70 mov [xDX + VMMR0JMPBUF.edi], edi
71 mov [xDX + VMMR0JMPBUF.ebp], ebp
72 mov xAX, [esp]
73 mov [xDX + VMMR0JMPBUF.eip], xAX
74 lea ecx, [esp + 4] ; (used in resume)
75 mov [xDX + VMMR0JMPBUF.esp], ecx
76 pushf
77 pop xAX
78 mov [xDX + VMMR0JMPBUF.eflags], xAX
79
80 ;
81 ; If we're not in a ring-3 call, call pfn and return.
82 ;
83 test byte [xDX + VMMR0JMPBUF.fInRing3Call], 1
84 jnz .resume
85
86 mov ebx, edx ; pJmpBuf -> ebx (persistent reg)
87%ifdef VMM_R0_SWITCH_STACK
88 mov esi, [ebx + VMMR0JMPBUF.pvSavedStack]
89 test esi, esi
90 jz .entry_error
91 %ifdef VBOX_STRICT
92 cmp dword [esi], 0h
93 jne .entry_error
94 mov edx, esi
95 mov edi, esi
96 mov ecx, VMM_STACK_SIZE / 4
97 mov eax, STACK_PADDING
98 repne stosd
99 %endif
100 lea esi, [esi + VMM_STACK_SIZE - 32]
101 mov [esi + 1ch], dword 0deadbeefh ; Marker 1.
102 mov [esi + 18h], ebx ; Save pJmpBuf pointer.
103 mov [esi + 14h], dword 00c00ffeeh ; Marker 2.
104 mov [esi + 10h], dword 0f00dbeefh ; Marker 3.
105 mov edx, [esp + 10h] ; pvArg2
106 mov ecx, [esp + 0ch] ; pvArg1
107 mov eax, [esp + 08h] ; pfn
108 %if 1 ; Use this to eat of some extra stack - handy for finding paths using lots of stack.
109 %define FRAME_OFFSET 0
110 %else
111 %define FRAME_OFFSET 1024
112 %endif
113 mov [esi - FRAME_OFFSET + 04h], edx
114 mov [esi - FRAME_OFFSET ], ecx
115 lea esp, [esi - FRAME_OFFSET] ; Switch stack!
116 call eax
117 and dword [esi + 1ch], byte 0 ; reset marker.
118
119 %ifdef VBOX_STRICT
120 ; Calc stack usage and check for overflows.
121 mov edi, [ebx + VMMR0JMPBUF.pvSavedStack]
122 cmp dword [edi], STACK_PADDING ; Check for obvious stack overflow.
123 jne .stack_overflow
124 mov esi, eax ; save eax
125 mov eax, STACK_PADDING
126 mov ecx, VMM_STACK_SIZE / 4
127 cld
128 repe scasd
129 shl ecx, 2 ; *4
130 cmp ecx, VMM_STACK_SIZE - 64 ; Less than 64 bytes left -> overflow as well.
131 mov eax, esi ; restore eax in case of overflow (esi remains used)
132 jae .stack_overflow_almost
133
134 ; Update stack usage statistics.
135 cmp ecx, [ebx + VMMR0JMPBUF.cbUsedMax] ; New max usage?
136 jle .no_used_max
137 mov [ebx + VMMR0JMPBUF.cbUsedMax], ecx
138.no_used_max:
139 ; To simplify the average stuff, just historize before we hit div errors.
140 inc dword [ebx + VMMR0JMPBUF.cUsedTotal]
141 test [ebx + VMMR0JMPBUF.cUsedTotal], dword 0c0000000h
142 jz .no_historize
143 mov dword [ebx + VMMR0JMPBUF.cUsedTotal], 2
144 mov edi, [ebx + VMMR0JMPBUF.cbUsedAvg]
145 mov [ebx + VMMR0JMPBUF.cbUsedTotal], edi
146 mov dword [ebx + VMMR0JMPBUF.cbUsedTotal + 4], 0
147.no_historize:
148 add [ebx + VMMR0JMPBUF.cbUsedTotal], ecx
149 adc dword [ebx + VMMR0JMPBUF.cbUsedTotal + 4], 0
150 mov eax, [ebx + VMMR0JMPBUF.cbUsedTotal]
151 mov edx, [ebx + VMMR0JMPBUF.cbUsedTotal + 4]
152 mov edi, [ebx + VMMR0JMPBUF.cUsedTotal]
153 div edi
154 mov [ebx + VMMR0JMPBUF.cbUsedAvg], eax
155
156 mov eax, esi ; restore eax (final, esi released)
157
158 mov edi, [ebx + VMMR0JMPBUF.pvSavedStack]
159 mov dword [edi], 0h ; Reset the overflow marker.
160 %endif ; VBOX_STRICT
161
162%else ; !VMM_R0_SWITCH_STACK
163 mov ecx, [esp + 0ch] ; pvArg1
164 mov edx, [esp + 10h] ; pvArg2
165 mov eax, [esp + 08h] ; pfn
166 sub esp, 12 ; align the stack on a 16-byte boundary.
167 mov [esp ], ecx
168 mov [esp + 04h], edx
169 call eax
170%endif ; !VMM_R0_SWITCH_STACK
171 mov edx, ebx ; pJmpBuf -> edx (volatile reg)
172
173 ;
174 ; Return like in the long jump but clear eip, no short cuts here.
175 ;
176.proper_return:
177 mov ebx, [xDX + VMMR0JMPBUF.ebx]
178 mov esi, [xDX + VMMR0JMPBUF.esi]
179 mov edi, [xDX + VMMR0JMPBUF.edi]
180 mov ebp, [xDX + VMMR0JMPBUF.ebp]
181 mov xCX, [xDX + VMMR0JMPBUF.eip]
182 and dword [xDX + VMMR0JMPBUF.eip], byte 0 ; used for valid check.
183 mov esp, [xDX + VMMR0JMPBUF.esp]
184 push dword [xDX + VMMR0JMPBUF.eflags]
185 popf
186 jmp xCX
187
188.entry_error:
189 mov eax, VERR_VMM_SET_JMP_ERROR
190 jmp .proper_return
191
192.stack_overflow:
193 mov eax, VERR_VMM_SET_JMP_STACK_OVERFLOW
194 mov edx, ebx
195 jmp .proper_return
196
197.stack_overflow_almost:
198 mov eax, VERR_VMM_SET_JMP_STACK_OVERFLOW
199 mov edx, ebx
200 jmp .proper_return
201
202 ;
203 ; Aborting resume.
204 ;
205.bad:
206 and dword [xDX + VMMR0JMPBUF.eip], byte 0 ; used for valid check.
207 mov edi, [xDX + VMMR0JMPBUF.edi]
208 mov esi, [xDX + VMMR0JMPBUF.esi]
209 mov ebx, [xDX + VMMR0JMPBUF.ebx]
210 mov eax, VERR_VMM_SET_JMP_ABORTED_RESUME
211 ret
212
213 ;
214 ; Resume VMMRZCallRing3 the call.
215 ;
216.resume:
217 ; Sanity checks.
218%ifdef VMM_R0_SWITCH_STACK
219 mov eax, [xDX + VMMR0JMPBUF.pvSavedStack]
220 %ifdef RT_STRICT
221 cmp dword [eax], STACK_PADDING
222 %endif
223 lea eax, [eax + VMM_STACK_SIZE - 32]
224 cmp dword [eax + 1ch], 0deadbeefh ; Marker 1.
225 jne .bad
226 %ifdef RT_STRICT
227 cmp [esi + 18h], edx ; The saved pJmpBuf pointer.
228 jne .bad
229 cmp dword [esi + 14h], 00c00ffeeh ; Marker 2.
230 jne .bad
231 cmp dword [esi + 10h], 0f00dbeefh ; Marker 3.
232 jne .bad
233 %endif
234%else ; !VMM_R0_SWITCH_STACK
235 cmp ecx, [xDX + VMMR0JMPBUF.SpCheck]
236 jne .bad
237.espCheck_ok:
238 mov ecx, [xDX + VMMR0JMPBUF.cbSavedStack]
239 cmp ecx, VMM_STACK_SIZE
240 ja .bad
241 test ecx, 3
242 jnz .bad
243 mov edi, [xDX + VMMR0JMPBUF.esp]
244 sub edi, [xDX + VMMR0JMPBUF.SpResume]
245 cmp ecx, edi
246 jne .bad
247%endif
248
249%ifdef VMM_R0_SWITCH_STACK
250 ; Switch stack.
251 mov esp, [xDX + VMMR0JMPBUF.SpResume]
252%else
253 ; Restore the stack.
254 mov ecx, [xDX + VMMR0JMPBUF.cbSavedStack]
255 shr ecx, 2
256 mov esi, [xDX + VMMR0JMPBUF.pvSavedStack]
257 mov edi, [xDX + VMMR0JMPBUF.SpResume]
258 mov esp, edi
259 rep movsd
260%endif ; !VMM_R0_SWITCH_STACK
261 mov byte [xDX + VMMR0JMPBUF.fInRing3Call], 0
262
263 ;
264 ; Continue where we left off.
265 ;
266%ifdef VBOX_STRICT
267 pop eax ; magic
268 cmp eax, RESUME_MAGIC
269 je .magic_ok
270 mov ecx, 0123h
271 mov [ecx], edx
272.magic_ok:
273%endif
274 popf
275 pop ebx
276 pop esi
277 pop edi
278 pop ebp
279 xor eax, eax ; VINF_SUCCESS
280 ret
281ENDPROC vmmR0CallRing3SetJmp
282
283
284;;
285; Worker for VMMRZCallRing3.
286; This will save the stack and registers.
287;
288; @param pJmpBuf msc:rcx gcc:rdi x86:[ebp+8] Pointer to the jump buffer.
289; @param rc msc:rdx gcc:rsi x86:[ebp+c] The return code.
290;
291BEGINPROC vmmR0CallRing3LongJmp
292 ;
293 ; Save the registers on the stack.
294 ;
295 push ebp
296 mov ebp, esp
297 push edi
298 push esi
299 push ebx
300 pushf
301%ifdef VBOX_STRICT
302 push RESUME_MAGIC
303%endif
304
305 ;
306 ; Load parameters.
307 ;
308 mov edx, [ebp + 08h] ; pJmpBuf
309 mov eax, [ebp + 0ch] ; rc
310
311 ;
312 ; Is the jump buffer armed?
313 ;
314 cmp dword [xDX + VMMR0JMPBUF.eip], byte 0
315 je .nok
316
317 ;
318 ; Sanity checks.
319 ;
320 mov edi, [xDX + VMMR0JMPBUF.pvSavedStack]
321 test edi, edi ; darwin may set this to 0.
322 jz .nok
323 mov [xDX + VMMR0JMPBUF.SpResume], esp
324%ifndef VMM_R0_SWITCH_STACK
325 mov esi, esp
326 mov ecx, [xDX + VMMR0JMPBUF.esp]
327 sub ecx, esi
328
329 ; two sanity checks on the size.
330 cmp ecx, VMM_STACK_SIZE ; check max size.
331 jnbe .nok
332
333 ;
334 ; Copy the stack.
335 ;
336 test ecx, 3 ; check alignment
337 jnz .nok
338 mov [xDX + VMMR0JMPBUF.cbSavedStack], ecx
339 shr ecx, 2
340 rep movsd
341%endif ; !VMM_R0_SWITCH_STACK
342
343 ; Save a PC here to assist unwinding.
344.unwind_point:
345 mov dword [xDX + VMMR0JMPBUF.SavedEipForUnwind], .unwind_point
346 mov ecx, [xDX + VMMR0JMPBUF.ebp]
347 lea ecx, [ecx + 4]
348 mov [xDX + VMMR0JMPBUF.UnwindRetPcLocation], ecx
349
350 ; Save ESP & EBP to enable stack dumps
351 mov ecx, ebp
352 mov [xDX + VMMR0JMPBUF.SavedEbp], ecx
353 sub ecx, 4
354 mov [xDX + VMMR0JMPBUF.SavedEsp], ecx
355
356 ; store the last pieces of info.
357 mov ecx, [xDX + VMMR0JMPBUF.esp]
358 mov [xDX + VMMR0JMPBUF.SpCheck], ecx
359 mov byte [xDX + VMMR0JMPBUF.fInRing3Call], 1
360
361 ;
362 ; Do the long jump.
363 ;
364 mov ebx, [xDX + VMMR0JMPBUF.ebx]
365 mov esi, [xDX + VMMR0JMPBUF.esi]
366 mov edi, [xDX + VMMR0JMPBUF.edi]
367 mov ebp, [xDX + VMMR0JMPBUF.ebp]
368 mov ecx, [xDX + VMMR0JMPBUF.eip]
369 mov [xDX + VMMR0JMPBUF.UnwindRetPcValue], ecx
370 mov esp, [xDX + VMMR0JMPBUF.esp]
371 push dword [xDX + VMMR0JMPBUF.eflags]
372 popf
373 jmp ecx
374
375 ;
376 ; Failure
377 ;
378.nok:
379%ifdef VBOX_STRICT
380 pop eax ; magic
381 cmp eax, RESUME_MAGIC
382 je .magic_ok
383 mov ecx, 0123h
384 mov [ecx], edx
385.magic_ok:
386%endif
387 popf
388 pop ebx
389 pop esi
390 pop edi
391 mov eax, VERR_VMM_LONG_JMP_ERROR
392 leave
393 ret
394ENDPROC vmmR0CallRing3LongJmp
395
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette