VirtualBox

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

Last change on this file since 20961 was 20875, checked in by vboxsync, 15 years ago

VMM: Renamed almost all references to CallHost to CallRing3.

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