VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/VMMR0JmpA-amd64.asm@ 66250

Last change on this file since 66250 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 12.9 KB
Line 
1; $Id: VMMR0JmpA-amd64.asm 62478 2016-07-22 18:29:06Z vboxsync $
2;; @file
3; VMM - R0 SetJmp / LongJmp routines for AMD64.
4;
5
6;
7; Copyright (C) 2006-2016 Oracle Corporation
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
18;*******************************************************************************
19;* Header Files *
20;*******************************************************************************
21%include "VBox/asmdefs.mac"
22%include "VMMInternal.mac"
23%include "VBox/err.mac"
24%include "VBox/param.mac"
25
26
27;*******************************************************************************
28;* Defined Constants And Macros *
29;*******************************************************************************
30%define RESUME_MAGIC 07eadf00dh
31%define STACK_PADDING 0eeeeeeeeeeeeeeeeh
32
33;; Workaround for linux 4.6 fast/slow syscall stack depth difference.
34%ifdef VMM_R0_SWITCH_STACK
35 %define STACK_FUZZ_SIZE 0
36%else
37 %define STACK_FUZZ_SIZE 128
38%endif
39
40
41BEGINCODE
42
43
44;;
45; The setjmp variant used for calling Ring-3.
46;
47; This differs from the normal setjmp in that it will resume VMMRZCallRing3 if we're
48; in the middle of a ring-3 call. Another differences is the function pointer and
49; argument. This has to do with resuming code and the stack frame of the caller.
50;
51; @returns VINF_SUCCESS on success or whatever is passed to vmmR0CallRing3LongJmp.
52; @param pJmpBuf msc:rcx gcc:rdi x86:[esp+0x04] Our jmp_buf.
53; @param pfn msc:rdx gcc:rsi x86:[esp+0x08] The function to be called when not resuming.
54; @param pvUser1 msc:r8 gcc:rdx x86:[esp+0x0c] The argument of that function.
55; @param pvUser2 msc:r9 gcc:rcx x86:[esp+0x10] The argument of that function.
56;
57BEGINPROC vmmR0CallRing3SetJmp
58GLOBALNAME vmmR0CallRing3SetJmpEx
59 ;
60 ; Save the registers.
61 ;
62 push rbp
63 mov rbp, rsp
64 %ifdef ASM_CALL64_MSC
65 sub rsp, 30h + STACK_FUZZ_SIZE ; (10h is used by resume (??), 20h for callee spill area)
66 mov r11, rdx ; pfn
67 mov rdx, rcx ; pJmpBuf;
68 %else
69 sub rsp, 10h + STACK_FUZZ_SIZE ; (10h is used by resume (??))
70 mov r8, rdx ; pvUser1 (save it like MSC)
71 mov r9, rcx ; pvUser2 (save it like MSC)
72 mov r11, rsi ; pfn
73 mov rdx, rdi ; pJmpBuf
74 %endif
75 mov [xDX + VMMR0JMPBUF.rbx], rbx
76 %ifdef ASM_CALL64_MSC
77 mov [xDX + VMMR0JMPBUF.rsi], rsi
78 mov [xDX + VMMR0JMPBUF.rdi], rdi
79 %endif
80 mov [xDX + VMMR0JMPBUF.rbp], rbp
81 mov [xDX + VMMR0JMPBUF.r12], r12
82 mov [xDX + VMMR0JMPBUF.r13], r13
83 mov [xDX + VMMR0JMPBUF.r14], r14
84 mov [xDX + VMMR0JMPBUF.r15], r15
85 mov xAX, [rbp + 8] ; (not really necessary, except for validity check)
86 mov [xDX + VMMR0JMPBUF.rip], xAX
87 %ifdef ASM_CALL64_MSC
88 lea r10, [rsp + 20h] ; must save the spill area
89 %else
90 lea r10, [rsp]
91 %endif
92 mov [xDX + VMMR0JMPBUF.rsp], r10
93 %ifdef RT_OS_WINDOWS
94 movdqa [xDX + VMMR0JMPBUF.xmm6], xmm6
95 movdqa [xDX + VMMR0JMPBUF.xmm7], xmm7
96 movdqa [xDX + VMMR0JMPBUF.xmm8], xmm8
97 movdqa [xDX + VMMR0JMPBUF.xmm9], xmm9
98 movdqa [xDX + VMMR0JMPBUF.xmm10], xmm10
99 movdqa [xDX + VMMR0JMPBUF.xmm11], xmm11
100 movdqa [xDX + VMMR0JMPBUF.xmm12], xmm12
101 movdqa [xDX + VMMR0JMPBUF.xmm13], xmm13
102 movdqa [xDX + VMMR0JMPBUF.xmm14], xmm14
103 movdqa [xDX + VMMR0JMPBUF.xmm15], xmm15
104 %endif
105 pushf
106 pop xAX
107 mov [xDX + VMMR0JMPBUF.rflags], xAX
108
109 ;
110 ; If we're not in a ring-3 call, call pfn and return.
111 ;
112 test byte [xDX + VMMR0JMPBUF.fInRing3Call], 1
113 jnz .resume
114
115 %ifdef VMM_R0_SWITCH_STACK
116 mov r15, [xDX + VMMR0JMPBUF.pvSavedStack]
117 test r15, r15
118 jz .entry_error
119 %ifdef VBOX_STRICT
120 cmp dword [r15], 0h
121 jne .entry_error
122 mov rdi, r15
123 mov rcx, VMM_STACK_SIZE / 8
124 mov rax, qword 0eeeeeeeffeeeeeeeh
125 repne stosq
126 mov [rdi - 10h], rbx
127 %endif
128 lea r15, [r15 + VMM_STACK_SIZE - 40h]
129 mov rsp, r15 ; Switch stack!
130 %endif ; VMM_R0_SWITCH_STACK
131
132 mov r12, rdx ; Save pJmpBuf.
133 %ifdef ASM_CALL64_MSC
134 mov rcx, r8 ; pvUser -> arg0
135 mov rdx, r9
136 %else
137 mov rdi, r8 ; pvUser -> arg0
138 mov rsi, r9
139 %endif
140 call r11
141 mov rdx, r12 ; Restore pJmpBuf
142
143 %ifdef VMM_R0_SWITCH_STACK
144 %ifdef VBOX_STRICT
145 mov r15, [xDX + VMMR0JMPBUF.pvSavedStack]
146 mov dword [r15], 0h ; Reset the marker
147 %endif
148 %endif
149
150 ;
151 ; Return like in the long jump but clear eip, no shortcuts here.
152 ;
153.proper_return:
154%ifdef RT_OS_WINDOWS
155 movdqa xmm6, [xDX + VMMR0JMPBUF.xmm6 ]
156 movdqa xmm7, [xDX + VMMR0JMPBUF.xmm7 ]
157 movdqa xmm8, [xDX + VMMR0JMPBUF.xmm8 ]
158 movdqa xmm9, [xDX + VMMR0JMPBUF.xmm9 ]
159 movdqa xmm10, [xDX + VMMR0JMPBUF.xmm10]
160 movdqa xmm11, [xDX + VMMR0JMPBUF.xmm11]
161 movdqa xmm12, [xDX + VMMR0JMPBUF.xmm12]
162 movdqa xmm13, [xDX + VMMR0JMPBUF.xmm13]
163 movdqa xmm14, [xDX + VMMR0JMPBUF.xmm14]
164 movdqa xmm15, [xDX + VMMR0JMPBUF.xmm15]
165%endif
166 mov rbx, [xDX + VMMR0JMPBUF.rbx]
167%ifdef ASM_CALL64_MSC
168 mov rsi, [xDX + VMMR0JMPBUF.rsi]
169 mov rdi, [xDX + VMMR0JMPBUF.rdi]
170%endif
171 mov r12, [xDX + VMMR0JMPBUF.r12]
172 mov r13, [xDX + VMMR0JMPBUF.r13]
173 mov r14, [xDX + VMMR0JMPBUF.r14]
174 mov r15, [xDX + VMMR0JMPBUF.r15]
175 mov rbp, [xDX + VMMR0JMPBUF.rbp]
176 and qword [xDX + VMMR0JMPBUF.rip], byte 0 ; used for valid check.
177 mov rsp, [xDX + VMMR0JMPBUF.rsp]
178 push qword [xDX + VMMR0JMPBUF.rflags]
179 popf
180 leave
181 ret
182
183.entry_error:
184 mov eax, VERR_VMM_SET_JMP_ERROR
185 jmp .proper_return
186
187.stack_overflow:
188 mov eax, VERR_VMM_SET_JMP_STACK_OVERFLOW
189 jmp .proper_return
190
191 ;
192 ; Aborting resume.
193 ; Note! No need to restore XMM registers here since we haven't touched them yet.
194 ;
195.bad:
196 and qword [xDX + VMMR0JMPBUF.rip], byte 0 ; used for valid check.
197 mov rbx, [xDX + VMMR0JMPBUF.rbx]
198 %ifdef ASM_CALL64_MSC
199 mov rsi, [xDX + VMMR0JMPBUF.rsi]
200 mov rdi, [xDX + VMMR0JMPBUF.rdi]
201 %endif
202 mov r12, [xDX + VMMR0JMPBUF.r12]
203 mov r13, [xDX + VMMR0JMPBUF.r13]
204 mov r14, [xDX + VMMR0JMPBUF.r14]
205 mov r15, [xDX + VMMR0JMPBUF.r15]
206 mov eax, VERR_VMM_SET_JMP_ABORTED_RESUME
207 leave
208 ret
209
210 ;
211 ; Resume VMMRZCallRing3 the call.
212 ;
213.resume:
214 %ifndef VMM_R0_SWITCH_STACK
215 ; Sanity checks incoming stack, applying fuzz if needed.
216 sub r10, [xDX + VMMR0JMPBUF.SpCheck]
217 jz .resume_stack_checked_out
218 add r10, STACK_FUZZ_SIZE ; plus/minus STACK_FUZZ_SIZE is fine.
219 cmp r10, STACK_FUZZ_SIZE * 2
220 ja .bad
221
222 mov r10, [xDX + VMMR0JMPBUF.SpCheck]
223 mov [xDX + VMMR0JMPBUF.rsp], r10 ; Must be update in case of another long jump (used for save calc).
224
225.resume_stack_checked_out:
226 mov ecx, [xDX + VMMR0JMPBUF.cbSavedStack]
227 cmp rcx, VMM_STACK_SIZE
228 ja .bad
229 test rcx, 7
230 jnz .bad
231 mov rdi, [xDX + VMMR0JMPBUF.SpCheck]
232 sub rdi, [xDX + VMMR0JMPBUF.SpResume]
233 cmp rcx, rdi
234 jne .bad
235 %endif
236
237%ifdef VMM_R0_SWITCH_STACK
238 ; Switch stack.
239 mov rsp, [xDX + VMMR0JMPBUF.SpResume]
240%else
241 ; Restore the stack.
242 mov ecx, [xDX + VMMR0JMPBUF.cbSavedStack]
243 shr ecx, 3
244 mov rsi, [xDX + VMMR0JMPBUF.pvSavedStack]
245 mov rdi, [xDX + VMMR0JMPBUF.SpResume]
246 mov rsp, rdi
247 rep movsq
248%endif ; !VMM_R0_SWITCH_STACK
249 mov byte [xDX + VMMR0JMPBUF.fInRing3Call], 0
250
251 ;
252 ; Continue where we left off.
253 ;
254%ifdef VBOX_STRICT
255 pop rax ; magic
256 cmp rax, RESUME_MAGIC
257 je .magic_ok
258 mov ecx, 0123h
259 mov [ecx], edx
260.magic_ok:
261%endif
262%ifdef RT_OS_WINDOWS
263 movdqa xmm6, [rsp + 000h]
264 movdqa xmm7, [rsp + 010h]
265 movdqa xmm8, [rsp + 020h]
266 movdqa xmm9, [rsp + 030h]
267 movdqa xmm10, [rsp + 040h]
268 movdqa xmm11, [rsp + 050h]
269 movdqa xmm12, [rsp + 060h]
270 movdqa xmm13, [rsp + 070h]
271 movdqa xmm14, [rsp + 080h]
272 movdqa xmm15, [rsp + 090h]
273 add rsp, 0a0h
274%endif
275 popf
276 pop rbx
277%ifdef ASM_CALL64_MSC
278 pop rsi
279 pop rdi
280%endif
281 pop r12
282 pop r13
283 pop r14
284 pop r15
285 pop rbp
286 xor eax, eax ; VINF_SUCCESS
287 ret
288ENDPROC vmmR0CallRing3SetJmp
289
290
291;;
292; Worker for VMMRZCallRing3.
293; This will save the stack and registers.
294;
295; @param pJmpBuf msc:rcx gcc:rdi x86:[ebp+8] Pointer to the jump buffer.
296; @param rc msc:rdx gcc:rsi x86:[ebp+c] The return code.
297;
298BEGINPROC vmmR0CallRing3LongJmp
299 ;
300 ; Save the registers on the stack.
301 ;
302 push rbp
303 mov rbp, rsp
304 push r15
305 push r14
306 push r13
307 push r12
308%ifdef ASM_CALL64_MSC
309 push rdi
310 push rsi
311%endif
312 push rbx
313 pushf
314%ifdef RT_OS_WINDOWS
315 sub rsp, 0a0h
316 movdqa [rsp + 000h], xmm6
317 movdqa [rsp + 010h], xmm7
318 movdqa [rsp + 020h], xmm8
319 movdqa [rsp + 030h], xmm9
320 movdqa [rsp + 040h], xmm10
321 movdqa [rsp + 050h], xmm11
322 movdqa [rsp + 060h], xmm12
323 movdqa [rsp + 070h], xmm13
324 movdqa [rsp + 080h], xmm14
325 movdqa [rsp + 090h], xmm15
326%endif
327%ifdef VBOX_STRICT
328 push RESUME_MAGIC
329%endif
330
331 ;
332 ; Normalize the parameters.
333 ;
334%ifdef ASM_CALL64_MSC
335 mov eax, edx ; rc
336 mov rdx, rcx ; pJmpBuf
337%else
338 mov rdx, rdi ; pJmpBuf
339 mov eax, esi ; rc
340%endif
341
342 ;
343 ; Is the jump buffer armed?
344 ;
345 cmp qword [xDX + VMMR0JMPBUF.rip], byte 0
346 je .nok
347
348 ;
349 ; Sanity checks.
350 ;
351 mov rdi, [xDX + VMMR0JMPBUF.pvSavedStack]
352 test rdi, rdi ; darwin may set this to 0.
353 jz .nok
354 mov [xDX + VMMR0JMPBUF.SpResume], rsp
355 %ifndef VMM_R0_SWITCH_STACK
356 mov rsi, rsp
357 mov rcx, [xDX + VMMR0JMPBUF.rsp]
358 sub rcx, rsi
359
360 ; two sanity checks on the size.
361 cmp rcx, VMM_STACK_SIZE ; check max size.
362 jnbe .nok
363
364 ;
365 ; Copy the stack
366 ;
367 test ecx, 7 ; check alignment
368 jnz .nok
369 mov [xDX + VMMR0JMPBUF.cbSavedStack], ecx
370 shr ecx, 3
371 rep movsq
372
373 %endif ; !VMM_R0_SWITCH_STACK
374
375 ; Save RSP & RBP to enable stack dumps
376 mov rcx, rbp
377 mov [xDX + VMMR0JMPBUF.SavedEbp], rcx
378 sub rcx, 8
379 mov [xDX + VMMR0JMPBUF.SavedEsp], rcx
380
381 ; store the last pieces of info.
382 mov rcx, [xDX + VMMR0JMPBUF.rsp]
383 mov [xDX + VMMR0JMPBUF.SpCheck], rcx
384 mov byte [xDX + VMMR0JMPBUF.fInRing3Call], 1
385
386 ;
387 ; Do the long jump.
388 ;
389%ifdef RT_OS_WINDOWS
390 movdqa xmm6, [xDX + VMMR0JMPBUF.xmm6 ]
391 movdqa xmm7, [xDX + VMMR0JMPBUF.xmm7 ]
392 movdqa xmm8, [xDX + VMMR0JMPBUF.xmm8 ]
393 movdqa xmm9, [xDX + VMMR0JMPBUF.xmm9 ]
394 movdqa xmm10, [xDX + VMMR0JMPBUF.xmm10]
395 movdqa xmm11, [xDX + VMMR0JMPBUF.xmm11]
396 movdqa xmm12, [xDX + VMMR0JMPBUF.xmm12]
397 movdqa xmm13, [xDX + VMMR0JMPBUF.xmm13]
398 movdqa xmm14, [xDX + VMMR0JMPBUF.xmm14]
399 movdqa xmm15, [xDX + VMMR0JMPBUF.xmm15]
400%endif
401 mov rbx, [xDX + VMMR0JMPBUF.rbx]
402%ifdef ASM_CALL64_MSC
403 mov rsi, [xDX + VMMR0JMPBUF.rsi]
404 mov rdi, [xDX + VMMR0JMPBUF.rdi]
405%endif
406 mov r12, [xDX + VMMR0JMPBUF.r12]
407 mov r13, [xDX + VMMR0JMPBUF.r13]
408 mov r14, [xDX + VMMR0JMPBUF.r14]
409 mov r15, [xDX + VMMR0JMPBUF.r15]
410 mov rbp, [xDX + VMMR0JMPBUF.rbp]
411 mov rsp, [xDX + VMMR0JMPBUF.rsp]
412 push qword [xDX + VMMR0JMPBUF.rflags]
413 popf
414 leave
415 ret
416
417 ;
418 ; Failure
419 ;
420.nok:
421%ifdef VBOX_STRICT
422 pop rax ; magic
423 cmp rax, RESUME_MAGIC
424 je .magic_ok
425 mov ecx, 0123h
426 mov [rcx], edx
427.magic_ok:
428%endif
429 mov eax, VERR_VMM_LONG_JMP_ERROR
430%ifdef RT_OS_WINDOWS
431 add rsp, 0a0h ; skip XMM registers since they are unmodified.
432%endif
433 popf
434 pop rbx
435%ifdef ASM_CALL64_MSC
436 pop rsi
437 pop rdi
438%endif
439 pop r12
440 pop r13
441 pop r14
442 pop r15
443 leave
444 ret
445ENDPROC vmmR0CallRing3LongJmp
446
447
448;;
449; Internal R0 logger worker: Logger wrapper.
450;
451; @cproto VMMR0DECL(void) vmmR0LoggerWrapper(const char *pszFormat, ...)
452;
453EXPORTEDNAME vmmR0LoggerWrapper
454 int3
455 int3
456 int3
457 ret
458ENDPROC vmmR0LoggerWrapper
459
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