VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months 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
RevLine 
[19]1; $Id: VMMR0JmpA-x86.asm 98103 2023-01-17 14:15:46Z vboxsync $
[1]2;; @file
[20541]3; VMM - R0 SetJmp / LongJmp routines for X86.
[1]4;
5
[19]6;
[98103]7; Copyright (C) 2006-2023 Oracle and/or its affiliates.
[4477]8;
[96407]9; This file is part of VirtualBox base platform packages, as
10; available from https://www.virtualbox.org.
[5999]11;
[96407]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;
[1]27
28;*******************************************************************************
29;* Header Files *
30;*******************************************************************************
[19]31%include "VBox/asmdefs.mac"
[35334]32%include "VMMInternal.mac"
[39404]33%include "VBox/err.mac"
[20543]34%include "VBox/param.mac"
[1]35
36
[20545]37;*******************************************************************************
38;* Defined Constants And Macros *
39;*******************************************************************************
40%define RESUME_MAGIC 07eadf00dh
41%define STACK_PADDING 0eeeeeeeeh
42
43
[1]44
45BEGINCODE
46
47
48;;
49; The setjmp variant used for calling Ring-3.
50;
[20874]51; This differs from the normal setjmp in that it will resume VMMRZCallRing3 if we're
[1]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;
[20875]55; @returns VINF_SUCCESS on success or whatever is passed to vmmR0CallRing3LongJmp.
[13872]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.
[1]60;
[20875]61BEGINPROC vmmR0CallRing3SetJmp
[71222]62GLOBALNAME vmmR0CallRing3SetJmp2
[20875]63GLOBALNAME vmmR0CallRing3SetJmpEx
[1]64 ;
65 ; Save the registers.
66 ;
67 mov edx, [esp + 4h] ; pJmpBuf
[20543]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
[1]74 lea ecx, [esp + 4] ; (used in resume)
[20543]75 mov [xDX + VMMR0JMPBUF.esp], ecx
[23487]76 pushf
77 pop xAX
78 mov [xDX + VMMR0JMPBUF.eflags], xAX
[1]79
80 ;
81 ; If we're not in a ring-3 call, call pfn and return.
82 ;
[20543]83 test byte [xDX + VMMR0JMPBUF.fInRing3Call], 1
[1]84 jnz .resume
85
[14672]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
[20534]92 cmp dword [esi], 0h
93 jne .entry_error
94 mov edx, esi
95 mov edi, esi
[20543]96 mov ecx, VMM_STACK_SIZE / 4
[20545]97 mov eax, STACK_PADDING
[14672]98 repne stosd
99 %endif
[20543]100 lea esi, [esi + VMM_STACK_SIZE - 32]
[14672]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
[13872]106 mov ecx, [esp + 0ch] ; pvArg1
[14672]107 mov eax, [esp + 08h] ; pfn
[30056]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
[20548]113 mov [esi - FRAME_OFFSET + 04h], edx
114 mov [esi - FRAME_OFFSET ], ecx
115 lea esp, [esi - FRAME_OFFSET] ; Switch stack!
[14672]116 call eax
[20545]117 and dword [esi + 1ch], byte 0 ; reset marker.
[14672]118
[20534]119 %ifdef VBOX_STRICT
[20545]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.
[20534]123 jne .stack_overflow
[20545]124 mov esi, eax ; save eax
125 mov eax, STACK_PADDING
126 mov ecx, VMM_STACK_SIZE / 4
127 cld
128 repe scasd
[20548]129 shl ecx, 2 ; *4
130 cmp ecx, VMM_STACK_SIZE - 64 ; Less than 64 bytes left -> overflow as well.
[20545]131 mov eax, esi ; restore eax in case of overflow (esi remains used)
132 jae .stack_overflow_almost
[20534]133
[20545]134 ; Update stack usage statistics.
[20548]135 cmp ecx, [ebx + VMMR0JMPBUF.cbUsedMax] ; New max usage?
[20545]136 jle .no_used_max
[20548]137 mov [ebx + VMMR0JMPBUF.cbUsedMax], ecx
[20545]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
[20548]144 mov edi, [ebx + VMMR0JMPBUF.cbUsedAvg]
145 mov [ebx + VMMR0JMPBUF.cbUsedTotal], edi
[20545]146 mov dword [ebx + VMMR0JMPBUF.cbUsedTotal + 4], 0
147.no_historize:
[20548]148 add [ebx + VMMR0JMPBUF.cbUsedTotal], ecx
[20545]149 adc dword [ebx + VMMR0JMPBUF.cbUsedTotal + 4], 0
150 mov eax, [ebx + VMMR0JMPBUF.cbUsedTotal]
151 mov edx, [ebx + VMMR0JMPBUF.cbUsedTotal + 4]
[20548]152 mov edi, [ebx + VMMR0JMPBUF.cUsedTotal]
153 div edi
[20545]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
[14672]162%else ; !VMM_R0_SWITCH_STACK
163 mov ecx, [esp + 0ch] ; pvArg1
[13872]164 mov edx, [esp + 10h] ; pvArg2
[1]165 mov eax, [esp + 08h] ; pfn
[33540]166 sub esp, 12 ; align the stack on a 16-byte boundary.
[14672]167 mov [esp ], ecx
168 mov [esp + 04h], edx
[1]169 call eax
[14672]170%endif ; !VMM_R0_SWITCH_STACK
171 mov edx, ebx ; pJmpBuf -> edx (volatile reg)
[7507]172
[14672]173 ;
[18849]174 ; Return like in the long jump but clear eip, no short cuts here.
[14672]175 ;
176.proper_return:
[20543]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]
[23487]184 push dword [xDX + VMMR0JMPBUF.eflags]
185 popf
[20543]186 jmp xCX
[1]187
[14672]188.entry_error:
[39402]189 mov eax, VERR_VMM_SET_JMP_ERROR
[14672]190 jmp .proper_return
191
[20534]192.stack_overflow:
[39402]193 mov eax, VERR_VMM_SET_JMP_STACK_OVERFLOW
[20545]194 mov edx, ebx
[20534]195 jmp .proper_return
196
[20545]197.stack_overflow_almost:
[39402]198 mov eax, VERR_VMM_SET_JMP_STACK_OVERFLOW
[20545]199 mov edx, ebx
200 jmp .proper_return
201
[1]202 ;
[20534]203 ; Aborting resume.
[1]204 ;
205.bad:
[20543]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]
[39402]210 mov eax, VERR_VMM_SET_JMP_ABORTED_RESUME
[1]211 ret
212
[20534]213 ;
[20874]214 ; Resume VMMRZCallRing3 the call.
[20534]215 ;
216.resume:
217 ; Sanity checks.
218%ifdef VMM_R0_SWITCH_STACK
[20543]219 mov eax, [xDX + VMMR0JMPBUF.pvSavedStack]
[20534]220 %ifdef RT_STRICT
[20545]221 cmp dword [eax], STACK_PADDING
[20534]222 %endif
[20543]223 lea eax, [eax + VMM_STACK_SIZE - 32]
[20534]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
[20543]235 cmp ecx, [xDX + VMMR0JMPBUF.SpCheck]
[20534]236 jne .bad
[1]237.espCheck_ok:
[20543]238 mov ecx, [xDX + VMMR0JMPBUF.cbSavedStack]
239 cmp ecx, VMM_STACK_SIZE
[1]240 ja .bad
241 test ecx, 3
242 jnz .bad
[20543]243 mov edi, [xDX + VMMR0JMPBUF.esp]
244 sub edi, [xDX + VMMR0JMPBUF.SpResume]
[1]245 cmp ecx, edi
246 jne .bad
[20534]247%endif
[1]248
[20534]249%ifdef VMM_R0_SWITCH_STACK
250 ; Switch stack.
[20543]251 mov esp, [xDX + VMMR0JMPBUF.SpResume]
[20534]252%else
[1]253 ; Restore the stack.
[20543]254 mov ecx, [xDX + VMMR0JMPBUF.cbSavedStack]
[1]255 shr ecx, 2
[20543]256 mov esi, [xDX + VMMR0JMPBUF.pvSavedStack]
257 mov edi, [xDX + VMMR0JMPBUF.SpResume]
[1]258 mov esp, edi
259 rep movsd
[14672]260%endif ; !VMM_R0_SWITCH_STACK
[20543]261 mov byte [xDX + VMMR0JMPBUF.fInRing3Call], 0
[1]262
[20543]263 ;
[1]264 ; Continue where we left off.
[20543]265 ;
[14672]266%ifdef VBOX_STRICT
267 pop eax ; magic
[20545]268 cmp eax, RESUME_MAGIC
[14672]269 je .magic_ok
270 mov ecx, 0123h
271 mov [ecx], edx
272.magic_ok:
273%endif
[1]274 popf
275 pop ebx
276 pop esi
277 pop edi
278 pop ebp
279 xor eax, eax ; VINF_SUCCESS
280 ret
[20875]281ENDPROC vmmR0CallRing3SetJmp
[1]282
283
284;;
[20874]285; Worker for VMMRZCallRing3.
[1]286; This will save the stack and registers.
287;
[726]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.
[1]290;
[20875]291BEGINPROC vmmR0CallRing3LongJmp
[1]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
[14672]301%ifdef VBOX_STRICT
[20545]302 push RESUME_MAGIC
[14672]303%endif
[1]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 ;
[20543]314 cmp dword [xDX + VMMR0JMPBUF.eip], byte 0
[1]315 je .nok
316
317 ;
[14672]318 ; Sanity checks.
[1]319 ;
[20543]320 mov edi, [xDX + VMMR0JMPBUF.pvSavedStack]
[14505]321 test edi, edi ; darwin may set this to 0.
322 jz .nok
[20543]323 mov [xDX + VMMR0JMPBUF.SpResume], esp
[14672]324%ifndef VMM_R0_SWITCH_STACK
[1]325 mov esi, esp
[20543]326 mov ecx, [xDX + VMMR0JMPBUF.esp]
[1]327 sub ecx, esi
328
329 ; two sanity checks on the size.
[20543]330 cmp ecx, VMM_STACK_SIZE ; check max size.
[14672]331 jnbe .nok
332
333 ;
334 ; Copy the stack.
335 ;
[1]336 test ecx, 3 ; check alignment
337 jnz .nok
[20543]338 mov [xDX + VMMR0JMPBUF.cbSavedStack], ecx
[1]339 shr ecx, 2
340 rep movsd
[14672]341%endif ; !VMM_R0_SWITCH_STACK
[1]342
[73471]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
[19575]350 ; Save ESP & EBP to enable stack dumps
351 mov ecx, ebp
[20543]352 mov [xDX + VMMR0JMPBUF.SavedEbp], ecx
[19575]353 sub ecx, 4
[20543]354 mov [xDX + VMMR0JMPBUF.SavedEsp], ecx
[19575]355
[1]356 ; store the last pieces of info.
[20543]357 mov ecx, [xDX + VMMR0JMPBUF.esp]
358 mov [xDX + VMMR0JMPBUF.SpCheck], ecx
359 mov byte [xDX + VMMR0JMPBUF.fInRing3Call], 1
[1]360
361 ;
362 ; Do the long jump.
363 ;
[20543]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]
[73471]369 mov [xDX + VMMR0JMPBUF.UnwindRetPcValue], ecx
[20543]370 mov esp, [xDX + VMMR0JMPBUF.esp]
[23487]371 push dword [xDX + VMMR0JMPBUF.eflags]
372 popf
[1]373 jmp ecx
[14672]374
375 ;
376 ; Failure
377 ;
378.nok:
379%ifdef VBOX_STRICT
380 pop eax ; magic
[20545]381 cmp eax, RESUME_MAGIC
[14672]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
[39402]391 mov eax, VERR_VMM_LONG_JMP_ERROR
[14672]392 leave
393 ret
[20875]394ENDPROC vmmR0CallRing3LongJmp
[1]395
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use