VirtualBox

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

Last change on this file since 93554 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 10.3 KB
Line 
1; $Id: VMMR0JmpA-amd64.asm 93115 2022-01-01 11:31:46Z vboxsync $
2;; @file
3; VMM - R0 SetJmp / LongJmp routines for AMD64.
4;
5
6;
7; Copyright (C) 2006-2022 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%define RT_ASM_WITH_SEH64_ALT
22%include "VBox/asmdefs.mac"
23%include "VMMInternal.mac"
24%include "VBox/err.mac"
25%include "VBox/param.mac"
26
27
28BEGINCODE
29
30;;
31; The setjmp variant used for calling Ring-3.
32;
33; This differs from the normal setjmp in that it will resume VMMRZCallRing3 if we're
34; in the middle of a ring-3 call. Another differences is the function pointer and
35; argument. This has to do with resuming code and the stack frame of the caller.
36;
37; @returns VINF_SUCCESS on success or whatever is passed to vmmR0CallRing3LongJmp.
38; @param pJmpBuf msc:rcx gcc:rdi x86:[esp+0x04] Our jmp_buf.
39; @param pfn msc:rdx gcc:rsi x86:[esp+0x08] The function to be called when not resuming.
40; @param pvUser1 msc:r8 gcc:rdx x86:[esp+0x0c] The argument of that function.
41; @param pvUser2 msc:r9 gcc:rcx x86:[esp+0x10] The argument of that function.
42;
43GLOBALNAME vmmR0CallRing3SetJmp2
44GLOBALNAME vmmR0CallRing3SetJmpEx
45BEGINPROC vmmR0CallRing3SetJmp
46 ;
47 ; Save the registers.
48 ;
49 push rbp
50 SEH64_PUSH_xBP
51 mov rbp, rsp
52 SEH64_SET_FRAME_xBP 0
53 %ifdef ASM_CALL64_MSC
54 sub rsp, 30h ; (10h is used by resume (??), 20h for callee spill area)
55 SEH64_ALLOCATE_STACK 30h
56SEH64_END_PROLOGUE
57 mov r11, rdx ; pfn
58 mov rdx, rcx ; pJmpBuf;
59 %else
60 sub rsp, 10h ; (10h is used by resume (??))
61 SEH64_ALLOCATE_STACK 10h
62SEH64_END_PROLOGUE
63 mov r8, rdx ; pvUser1 (save it like MSC)
64 mov r9, rcx ; pvUser2 (save it like MSC)
65 mov r11, rsi ; pfn
66 mov rdx, rdi ; pJmpBuf
67 %endif
68 mov [xDX + VMMR0JMPBUF.rbx], rbx
69 %ifdef ASM_CALL64_MSC
70 mov [xDX + VMMR0JMPBUF.rsi], rsi
71 mov [xDX + VMMR0JMPBUF.rdi], rdi
72 %endif
73 mov [xDX + VMMR0JMPBUF.rbp], rbp
74 mov [xDX + VMMR0JMPBUF.r12], r12
75 mov [xDX + VMMR0JMPBUF.r13], r13
76 mov [xDX + VMMR0JMPBUF.r14], r14
77 mov [xDX + VMMR0JMPBUF.r15], r15
78 mov xAX, [rbp + 8] ; (not really necessary, except for validity check)
79 mov [xDX + VMMR0JMPBUF.rip], xAX
80 %ifdef ASM_CALL64_MSC
81 lea r10, [rsp + 20h] ; must save the spill area
82 %else
83 lea r10, [rsp]
84 %endif
85 mov [xDX + VMMR0JMPBUF.rsp], r10
86 %ifdef RT_OS_WINDOWS
87 movdqa [xDX + VMMR0JMPBUF.xmm6], xmm6
88 movdqa [xDX + VMMR0JMPBUF.xmm7], xmm7
89 movdqa [xDX + VMMR0JMPBUF.xmm8], xmm8
90 movdqa [xDX + VMMR0JMPBUF.xmm9], xmm9
91 movdqa [xDX + VMMR0JMPBUF.xmm10], xmm10
92 movdqa [xDX + VMMR0JMPBUF.xmm11], xmm11
93 movdqa [xDX + VMMR0JMPBUF.xmm12], xmm12
94 movdqa [xDX + VMMR0JMPBUF.xmm13], xmm13
95 movdqa [xDX + VMMR0JMPBUF.xmm14], xmm14
96 movdqa [xDX + VMMR0JMPBUF.xmm15], xmm15
97 %endif
98 pushf
99 pop xAX
100 mov [xDX + VMMR0JMPBUF.rflags], xAX
101
102 ;
103 ; Save the call then make it.
104 ;
105 mov [xDX + VMMR0JMPBUF.pfn], r11
106 mov [xDX + VMMR0JMPBUF.pvUser1], r8
107 mov [xDX + VMMR0JMPBUF.pvUser2], r9
108
109 mov r12, rdx ; Save pJmpBuf.
110 %ifdef ASM_CALL64_MSC
111 mov rcx, r8 ; pvUser -> arg0
112 mov rdx, r9
113 %else
114 mov rdi, r8 ; pvUser -> arg0
115 mov rsi, r9
116 %endif
117 call r11
118 mov rdx, r12 ; Restore pJmpBuf
119
120 ;
121 ; Return like in the long jump but clear eip, no shortcuts here.
122 ;
123.proper_return:
124%ifdef RT_OS_WINDOWS
125 movdqa xmm6, [xDX + VMMR0JMPBUF.xmm6 ]
126 movdqa xmm7, [xDX + VMMR0JMPBUF.xmm7 ]
127 movdqa xmm8, [xDX + VMMR0JMPBUF.xmm8 ]
128 movdqa xmm9, [xDX + VMMR0JMPBUF.xmm9 ]
129 movdqa xmm10, [xDX + VMMR0JMPBUF.xmm10]
130 movdqa xmm11, [xDX + VMMR0JMPBUF.xmm11]
131 movdqa xmm12, [xDX + VMMR0JMPBUF.xmm12]
132 movdqa xmm13, [xDX + VMMR0JMPBUF.xmm13]
133 movdqa xmm14, [xDX + VMMR0JMPBUF.xmm14]
134 movdqa xmm15, [xDX + VMMR0JMPBUF.xmm15]
135%endif
136 mov rbx, [xDX + VMMR0JMPBUF.rbx]
137%ifdef ASM_CALL64_MSC
138 mov rsi, [xDX + VMMR0JMPBUF.rsi]
139 mov rdi, [xDX + VMMR0JMPBUF.rdi]
140%endif
141 mov r12, [xDX + VMMR0JMPBUF.r12]
142 mov r13, [xDX + VMMR0JMPBUF.r13]
143 mov r14, [xDX + VMMR0JMPBUF.r14]
144 mov r15, [xDX + VMMR0JMPBUF.r15]
145 mov rbp, [xDX + VMMR0JMPBUF.rbp]
146 and qword [xDX + VMMR0JMPBUF.rip], byte 0 ; used for valid check.
147 mov rsp, [xDX + VMMR0JMPBUF.rsp]
148 push qword [xDX + VMMR0JMPBUF.rflags]
149 popf
150 leave
151 ret
152ENDPROC vmmR0CallRing3SetJmp
153
154
155;;
156; Worker for VMMRZCallRing3.
157; This will save the stack and registers.
158;
159; @param pJmpBuf msc:rcx gcc:rdi x86:[ebp+8] Pointer to the jump buffer.
160; @param rc msc:rdx gcc:rsi x86:[ebp+c] The return code.
161;
162BEGINPROC vmmR0CallRing3LongJmp
163 ;
164 ; Save the registers on the stack.
165 ;
166 push rbp
167 SEH64_PUSH_xBP
168 mov rbp, rsp
169 SEH64_SET_FRAME_xBP 0
170 push r15
171 SEH64_PUSH_GREG r15
172 push r14
173 SEH64_PUSH_GREG r14
174 push r13
175 SEH64_PUSH_GREG r13
176 push r12
177 SEH64_PUSH_GREG r12
178%ifdef ASM_CALL64_MSC
179 push rdi
180 SEH64_PUSH_GREG rdi
181 push rsi
182 SEH64_PUSH_GREG rsi
183%endif
184 push rbx
185 SEH64_PUSH_GREG rbx
186 pushf
187 SEH64_ALLOCATE_STACK 8
188%ifdef RT_OS_WINDOWS
189 sub rsp, 0a0h
190 SEH64_ALLOCATE_STACK 0a0h
191 movdqa [rsp + 000h], xmm6
192 movdqa [rsp + 010h], xmm7
193 movdqa [rsp + 020h], xmm8
194 movdqa [rsp + 030h], xmm9
195 movdqa [rsp + 040h], xmm10
196 movdqa [rsp + 050h], xmm11
197 movdqa [rsp + 060h], xmm12
198 movdqa [rsp + 070h], xmm13
199 movdqa [rsp + 080h], xmm14
200 movdqa [rsp + 090h], xmm15
201%endif
202SEH64_END_PROLOGUE
203
204 ;
205 ; Normalize the parameters.
206 ;
207%ifdef ASM_CALL64_MSC
208 mov eax, edx ; rc
209 mov rdx, rcx ; pJmpBuf
210%else
211 mov rdx, rdi ; pJmpBuf
212 mov eax, esi ; rc
213%endif
214
215 ;
216 ; Is the jump buffer armed?
217 ;
218 cmp qword [xDX + VMMR0JMPBUF.rip], byte 0
219 je .nok
220
221 ;
222 ; Also check that the stack is in the vicinity of the RSP we entered
223 ; on so the stack mirroring below doesn't go wild.
224 ;
225 mov rsi, rsp
226 mov rcx, [xDX + VMMR0JMPBUF.rsp]
227 sub rcx, rsi
228 cmp rcx, _64K
229 jnbe .nok
230
231 ;
232 ; Save a PC and return PC here to assist unwinding.
233 ;
234.unwind_point:
235 lea rcx, [.unwind_point wrt RIP]
236 mov [xDX + VMMR0JMPBUF.UnwindPc], rcx
237 mov rcx, [xDX + VMMR0JMPBUF.rbp]
238 lea rcx, [rcx + 8]
239 mov [xDX + VMMR0JMPBUF.UnwindRetPcLocation], rcx
240 mov rcx, [rcx]
241 mov [xDX + VMMR0JMPBUF.UnwindRetPcValue], rcx
242
243 ; Save RSP & RBP to enable stack dumps
244 mov [xDX + VMMR0JMPBUF.UnwindSp], rsp
245 mov rcx, rbp
246 mov [xDX + VMMR0JMPBUF.UnwindBp], rcx
247 sub rcx, 8
248 mov [xDX + VMMR0JMPBUF.UnwindRetSp], rcx
249
250 ;
251 ; Make sure the direction flag is clear before we do any rep movsb below.
252 ;
253 cld
254
255 ;
256 ; Mirror the stack.
257 ;
258 xor ebx, ebx
259
260 mov rdi, [xDX + VMMR0JMPBUF.pvStackBuf]
261 or rdi, rdi
262 jz .skip_stack_mirroring
263
264 mov ebx, [xDX + VMMR0JMPBUF.cbStackBuf]
265 or ebx, ebx
266 jz .skip_stack_mirroring
267
268 mov rcx, [xDX + VMMR0JMPBUF.rsp]
269 sub rcx, rsp
270 and rcx, ~0fffh ; copy up to the page boundrary
271
272 cmp rcx, rbx ; rbx = rcx = RT_MIN(rbx, rcx);
273 jbe .do_stack_buffer_big_enough
274 mov ecx, ebx ; too much to copy, limit to ebx
275 jmp .do_stack_copying
276.do_stack_buffer_big_enough:
277 mov ebx, ecx ; ecx is smaller, update ebx for cbStackValid
278
279.do_stack_copying:
280 mov rsi, rsp
281 rep movsb
282
283.skip_stack_mirroring:
284 mov [xDX + VMMR0JMPBUF.cbStackValid], ebx
285
286 ;
287 ; Do buffer mirroring.
288 ;
289 mov rdi, [xDX + VMMR0JMPBUF.pMirrorBuf]
290 or rdi, rdi
291 jz .skip_buffer_mirroring
292 mov rsi, rdx
293 mov ecx, VMMR0JMPBUF_size
294 rep movsb
295.skip_buffer_mirroring:
296
297 ;
298 ; Do the long jump.
299 ;
300%ifdef RT_OS_WINDOWS
301 movdqa xmm6, [xDX + VMMR0JMPBUF.xmm6 ]
302 movdqa xmm7, [xDX + VMMR0JMPBUF.xmm7 ]
303 movdqa xmm8, [xDX + VMMR0JMPBUF.xmm8 ]
304 movdqa xmm9, [xDX + VMMR0JMPBUF.xmm9 ]
305 movdqa xmm10, [xDX + VMMR0JMPBUF.xmm10]
306 movdqa xmm11, [xDX + VMMR0JMPBUF.xmm11]
307 movdqa xmm12, [xDX + VMMR0JMPBUF.xmm12]
308 movdqa xmm13, [xDX + VMMR0JMPBUF.xmm13]
309 movdqa xmm14, [xDX + VMMR0JMPBUF.xmm14]
310 movdqa xmm15, [xDX + VMMR0JMPBUF.xmm15]
311%endif
312 mov rbx, [xDX + VMMR0JMPBUF.rbx]
313%ifdef ASM_CALL64_MSC
314 mov rsi, [xDX + VMMR0JMPBUF.rsi]
315 mov rdi, [xDX + VMMR0JMPBUF.rdi]
316%endif
317 mov r12, [xDX + VMMR0JMPBUF.r12]
318 mov r13, [xDX + VMMR0JMPBUF.r13]
319 mov r14, [xDX + VMMR0JMPBUF.r14]
320 mov r15, [xDX + VMMR0JMPBUF.r15]
321 mov rbp, [xDX + VMMR0JMPBUF.rbp]
322 mov rsp, [xDX + VMMR0JMPBUF.rsp]
323 push qword [xDX + VMMR0JMPBUF.rflags]
324 popf
325 leave
326 ret
327
328 ;
329 ; Failure
330 ;
331.nok:
332 mov eax, VERR_VMM_LONG_JMP_ERROR
333%ifdef RT_OS_WINDOWS
334 add rsp, 0a0h ; skip XMM registers since they are unmodified.
335%endif
336 popf
337 pop rbx
338%ifdef ASM_CALL64_MSC
339 pop rsi
340 pop rdi
341%endif
342 pop r12
343 pop r13
344 pop r14
345 pop r15
346 leave
347 ret
348ENDPROC vmmR0CallRing3LongJmp
349
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