VirtualBox

source: vbox/trunk/src/VBox/VMM/PATM/PATMA.asm@ 277

Last change on this file since 277 was 277, checked in by vboxsync, 18 years ago

Changed detection of pending guest interrupts & event in generated iret code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 59.2 KB
Line 
1; $Id: PATMA.asm 277 2007-01-24 14:43:42Z vboxsync $
2;; @file
3; PATM Assembly Routines.
4;
5
6; Copyright (C) 2006 InnoTek Systemberatung GmbH
7;
8; This file is part of VirtualBox Open Source Edition (OSE), as
9; available from http://www.virtualbox.org. This file is free software;
10; you can redistribute it and/or modify it under the terms of the GNU
11; General Public License as published by the Free Software Foundation,
12; in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
13; distribution. VirtualBox OSE is distributed in the hope that it will
14; be useful, but WITHOUT ANY WARRANTY of any kind.
15;
16; If you received this file as part of a commercial VirtualBox
17; distribution, then only the terms of your commercial VirtualBox
18; license agreement apply instead of the previous paragraph.
19
20;
21; @note This method has problems in theory. If we fault for any reason, then we won't be able to restore
22; the guest's context properly!!
23; E.g if one of the push instructions causes a fault or SS isn't wide open and our patch GC state accesses aren't valid.
24; @assumptions
25; - Enough stack for a few pushes
26; - The SS selector has base 0 and limit 0xffffffff
27;
28; @todo stack probing is currently hardcoded and not present everywhere (search for 'probe stack')
29
30
31;*******************************************************************************
32;* Header Files *
33;*******************************************************************************
34%include "VBox/asmdefs.mac"
35%include "VBox/err.mac"
36%include "VBox/x86.mac"
37%include "VBox/vm.mac"
38%include "PATMA.mac"
39
40
41BEGINCODE
42
43%ifdef __AMD64__
44 BITS 32 ; switch to 32-bit mode (x86).
45%endif
46
47%ifdef VBOX_WITH_STATISTICS
48;
49; Patch call statistics
50;
51BEGINPROC PATMStats
52PATMStats_Start:
53 mov dword [ss:PATM_INTERRUPTFLAG], 0
54 pushf
55 inc dword [ss:PATM_ALLPATCHCALLS]
56 inc dword [ss:PATM_PERPATCHCALLS]
57 popf
58 mov dword [ss:PATM_INTERRUPTFLAG], 1
59PATMStats_End:
60ENDPROC PATMStats
61
62
63; Patch record for statistics
64GLOBALNAME PATMStatsRecord
65 RTCCPTR_DEF PATMStats_Start
66 DD 0
67 DD 0
68 DD 0
69 DD PATMStats_End - PATMStats_Start
70 DD 4
71 DD PATM_INTERRUPTFLAG
72 DD 0
73 DD PATM_ALLPATCHCALLS
74 DD 0
75 DD PATM_PERPATCHCALLS
76 DD 0
77 DD PATM_INTERRUPTFLAG
78 DD 0
79 DD 0ffffffffh
80%endif
81
82;
83; Set PATM_INTERRUPTFLAG
84;
85BEGINPROC PATMSetPIF
86PATMSetPIF_Start:
87 mov dword [ss:PATM_INTERRUPTFLAG], 1
88PATMSetPIF_End:
89ENDPROC PATMSetPIF
90
91
92; Patch record for setting PATM_INTERRUPTFLAG
93GLOBALNAME PATMSetPIFRecord
94 RTCCPTR_DEF PATMSetPIF_Start
95 DD 0
96 DD 0
97 DD 0
98 DD PATMSetPIF_End - PATMSetPIF_Start
99 DD 1
100 DD PATM_INTERRUPTFLAG
101 DD 0
102 DD 0ffffffffh
103
104;
105; Clear PATM_INTERRUPTFLAG
106;
107BEGINPROC PATMClearPIF
108PATMClearPIF_Start:
109 ; probe stack here as we can't recover from page faults later on
110 not dword [esp-64]
111 not dword [esp-64]
112 mov dword [ss:PATM_INTERRUPTFLAG], 0
113PATMClearPIF_End:
114ENDPROC PATMClearPIF
115
116
117; Patch record for clearing PATM_INTERRUPTFLAG
118GLOBALNAME PATMClearPIFRecord
119 RTCCPTR_DEF PATMClearPIF_Start
120 DD 0
121 DD 0
122 DD 0
123 DD PATMClearPIF_End - PATMClearPIF_Start
124 DD 1
125 DD PATM_INTERRUPTFLAG
126 DD 0
127 DD 0ffffffffh
128
129;
130; Clear PATM_INHIBITIRQADDR and fault if IF=0
131;
132BEGINPROC PATMClearInhibitIRQFaultIF0
133PATMClearInhibitIRQFaultIF0_Start:
134 mov dword [ss:PATM_INTERRUPTFLAG], 0
135 mov dword [ss:PATM_INHIBITIRQADDR], 0
136 pushf
137
138 test dword [ss:PATM_VMFLAGS], X86_EFL_IF
139 jz PATMClearInhibitIRQFaultIF0_Fault
140
141 ; if interrupts are pending, then we must go back to the host context to handle them!
142 test dword [ss:PATM_VM_FORCEDACTIONS], VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_TIMER | VM_FF_REQUEST
143 jz PATMClearInhibitIRQFaultIF0_Continue
144
145 ; Go to our hypervisor trap handler to dispatch the pending irq
146 mov dword [ss:PATM_TEMP_EAX], eax
147 mov dword [ss:PATM_TEMP_ECX], ecx
148 mov dword [ss:PATM_TEMP_EDI], edi
149 mov dword [ss:PATM_TEMP_RESTORE_FLAGS], PATM_RESTORE_EAX | PATM_RESTORE_ECX | PATM_RESTORE_EDI
150 mov eax, PATM_ACTION_DISPATCH_PENDING_IRQ
151 lock or dword [ss:PATM_PENDINGACTION], eax
152 mov ecx, PATM_ACTION_MAGIC
153 mov edi, PATM_NEXTINSTRADDR
154 popfd ; restore flags we pushed above (the or instruction changes the flags as well)
155 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
156 ; does not return
157
158PATMClearInhibitIRQFaultIF0_Fault:
159 popf
160 mov dword [ss:PATM_INTERRUPTFLAG], 1
161 PATM_INT3
162
163PATMClearInhibitIRQFaultIF0_Continue:
164 popf
165 mov dword [ss:PATM_INTERRUPTFLAG], 1
166PATMClearInhibitIRQFaultIF0_End:
167ENDPROC PATMClearInhibitIRQFaultIF0
168
169
170; Patch record for clearing PATM_INHIBITIRQADDR
171GLOBALNAME PATMClearInhibitIRQFaultIF0Record
172 RTCCPTR_DEF PATMClearInhibitIRQFaultIF0_Start
173 DD 0
174 DD 0
175 DD 0
176 DD PATMClearInhibitIRQFaultIF0_End - PATMClearInhibitIRQFaultIF0_Start
177 DD 12
178 DD PATM_INTERRUPTFLAG
179 DD 0
180 DD PATM_INHIBITIRQADDR
181 DD 0
182 DD PATM_VMFLAGS
183 DD 0
184 DD PATM_VM_FORCEDACTIONS
185 DD 0
186 DD PATM_TEMP_EAX
187 DD 0
188 DD PATM_TEMP_ECX
189 DD 0
190 DD PATM_TEMP_EDI
191 DD 0
192 DD PATM_TEMP_RESTORE_FLAGS
193 DD 0
194 DD PATM_PENDINGACTION
195 DD 0
196 DD PATM_NEXTINSTRADDR
197 DD 0
198 DD PATM_INTERRUPTFLAG
199 DD 0
200 DD PATM_INTERRUPTFLAG
201 DD 0
202 DD 0ffffffffh
203
204;
205; Clear PATM_INHIBITIRQADDR and continue if IF=0 (duplicated function only; never jump back to guest code afterwards!!)
206;
207BEGINPROC PATMClearInhibitIRQContIF0
208PATMClearInhibitIRQContIF0_Start:
209 mov dword [ss:PATM_INTERRUPTFLAG], 0
210 mov dword [ss:PATM_INHIBITIRQADDR], 0
211 pushf
212
213 test dword [ss:PATM_VMFLAGS], X86_EFL_IF
214 jz PATMClearInhibitIRQContIF0_Continue
215
216 ; if interrupts are pending, then we must go back to the host context to handle them!
217 test dword [ss:PATM_VM_FORCEDACTIONS], VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_TIMER | VM_FF_REQUEST
218 jz PATMClearInhibitIRQContIF0_Continue
219
220 ; Go to our hypervisor trap handler to dispatch the pending irq
221 mov dword [ss:PATM_TEMP_EAX], eax
222 mov dword [ss:PATM_TEMP_ECX], ecx
223 mov dword [ss:PATM_TEMP_EDI], edi
224 mov dword [ss:PATM_TEMP_RESTORE_FLAGS], PATM_RESTORE_EAX | PATM_RESTORE_ECX | PATM_RESTORE_EDI
225 mov eax, PATM_ACTION_DISPATCH_PENDING_IRQ
226 lock or dword [ss:PATM_PENDINGACTION], eax
227 mov ecx, PATM_ACTION_MAGIC
228 mov edi, PATM_NEXTINSTRADDR
229 popfd ; restore flags we pushed above (the or instruction changes the flags as well)
230 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
231 ; does not return
232
233PATMClearInhibitIRQContIF0_Continue:
234 popf
235 mov dword [ss:PATM_INTERRUPTFLAG], 1
236PATMClearInhibitIRQContIF0_End:
237ENDPROC PATMClearInhibitIRQContIF0
238
239
240; Patch record for clearing PATM_INHIBITIRQADDR
241GLOBALNAME PATMClearInhibitIRQContIF0Record
242 RTCCPTR_DEF PATMClearInhibitIRQContIF0_Start
243 DD 0
244 DD 0
245 DD 0
246 DD PATMClearInhibitIRQContIF0_End - PATMClearInhibitIRQContIF0_Start
247 DD 11
248 DD PATM_INTERRUPTFLAG
249 DD 0
250 DD PATM_INHIBITIRQADDR
251 DD 0
252 DD PATM_VMFLAGS
253 DD 0
254 DD PATM_VM_FORCEDACTIONS
255 DD 0
256 DD PATM_TEMP_EAX
257 DD 0
258 DD PATM_TEMP_ECX
259 DD 0
260 DD PATM_TEMP_EDI
261 DD 0
262 DD PATM_TEMP_RESTORE_FLAGS
263 DD 0
264 DD PATM_PENDINGACTION
265 DD 0
266 DD PATM_NEXTINSTRADDR
267 DD 0
268 DD PATM_INTERRUPTFLAG
269 DD 0
270 DD 0ffffffffh
271
272
273BEGINPROC PATMCliReplacement
274PATMCliStart:
275 mov dword [ss:PATM_INTERRUPTFLAG], 0
276 pushf
277%ifdef PATM_LOG_IF_CHANGES
278 push eax
279 push ecx
280 mov eax, PATM_ACTION_LOG_CLI
281 lock or dword [ss:PATM_PENDINGACTION], eax
282 mov ecx, PATM_ACTION_MAGIC
283 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
284 pop ecx
285 pop eax
286%endif
287
288 and dword [ss:PATM_VMFLAGS], ~X86_EFL_IF
289 popf
290
291 mov dword [ss:PATM_INTERRUPTFLAG], 1
292 DB 0xE9
293PATMCliJump:
294 DD PATM_JUMPDELTA
295PATMCliEnd:
296ENDPROC PATMCliReplacement
297
298
299; Patch record for 'cli'
300GLOBALNAME PATMCliRecord
301 RTCCPTR_DEF PATMCliStart
302 DD PATMCliJump - PATMCliStart
303 DD 0
304 DD 0
305 DD PATMCliEnd - PATMCliStart
306%ifdef PATM_LOG_IF_CHANGES
307 DD 4
308%else
309 DD 3
310%endif
311 DD PATM_INTERRUPTFLAG
312 DD 0
313%ifdef PATM_LOG_IF_CHANGES
314 DD PATM_PENDINGACTION
315 DD 0
316%endif
317 DD PATM_VMFLAGS
318 DD 0
319 DD PATM_INTERRUPTFLAG
320 DD 0
321 DD 0ffffffffh
322
323
324BEGINPROC PATMStiReplacement
325PATMStiStart:
326 mov dword [ss:PATM_INTERRUPTFLAG], 0
327 mov dword [ss:PATM_INHIBITIRQADDR], PATM_NEXTINSTRADDR
328 pushf
329%ifdef PATM_LOG_IF_CHANGES
330 push eax
331 push ecx
332 mov eax, PATM_ACTION_LOG_STI
333 lock or dword [ss:PATM_PENDINGACTION], eax
334 mov ecx, PATM_ACTION_MAGIC
335 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
336 pop ecx
337 pop eax
338%endif
339 or dword [ss:PATM_VMFLAGS], X86_EFL_IF
340 popf
341 mov dword [ss:PATM_INTERRUPTFLAG], 1
342PATMStiEnd:
343ENDPROC PATMStiReplacement
344
345; Patch record for 'sti'
346GLOBALNAME PATMStiRecord
347 RTCCPTR_DEF PATMStiStart
348 DD 0
349 DD 0
350 DD 0
351 DD PATMStiEnd - PATMStiStart
352%ifdef PATM_LOG_IF_CHANGES
353 DD 6
354%else
355 DD 5
356%endif
357 DD PATM_INTERRUPTFLAG
358 DD 0
359 DD PATM_INHIBITIRQADDR
360 DD 0
361 DD PATM_NEXTINSTRADDR
362 DD 0
363%ifdef PATM_LOG_IF_CHANGES
364 DD PATM_PENDINGACTION
365 DD 0
366%endif
367 DD PATM_VMFLAGS
368 DD 0
369 DD PATM_INTERRUPTFLAG
370 DD 0
371 DD 0ffffffffh
372
373;
374; Trampoline code for trap entry (without error code on the stack)
375;
376; esp + 16 - SS (if transfer to inner ring)
377; esp + 12 - ESP (if transfer to inner ring)
378; esp + 8 - EFLAGS
379; esp + 4 - CS
380; esp - EIP
381;
382BEGINPROC PATMTrapEntry
383PATMTrapEntryStart:
384 mov dword [ss:PATM_INTERRUPTFLAG], 0
385 pushf
386
387 ; make sure the saved CS selector for ring 1 is made 0
388 test dword [esp+8], 2
389 jnz PATMTrapNoRing1
390 test dword [esp+8], 1
391 jz PATMTrapNoRing1
392 and dword [esp+8], dword ~1 ; yasm / nasm dword
393PATMTrapNoRing1:
394
395 ; correct EFLAGS on the stack to include the current IOPL
396 push eax
397 mov eax, dword [ss:PATM_VMFLAGS]
398 and eax, X86_EFL_IOPL
399 and dword [esp+16], ~X86_EFL_IOPL ; esp+16 = eflags = esp+8+4(efl)+4(eax)
400 or dword [esp+16], eax
401 pop eax
402
403 popf
404 mov dword [ss:PATM_INTERRUPTFLAG], 1
405 DB 0xE9
406PATMTrapEntryJump:
407 DD PATM_JUMPDELTA
408PATMTrapEntryEnd:
409ENDPROC PATMTrapEntry
410
411
412; Patch record for trap gate entrypoint
413GLOBALNAME PATMTrapEntryRecord
414 RTCCPTR_DEF PATMTrapEntryStart
415 DD PATMTrapEntryJump - PATMTrapEntryStart
416 DD 0
417 DD 0
418 DD PATMTrapEntryEnd - PATMTrapEntryStart
419 DD 3
420 DD PATM_INTERRUPTFLAG
421 DD 0
422 DD PATM_VMFLAGS
423 DD 0
424 DD PATM_INTERRUPTFLAG
425 DD 0
426 DD 0ffffffffh
427
428;
429; Trampoline code for trap entry (with error code on the stack)
430;
431; esp + 20 - SS (if transfer to inner ring)
432; esp + 16 - ESP (if transfer to inner ring)
433; esp + 12 - EFLAGS
434; esp + 8 - CS
435; esp + 4 - EIP
436; esp - error code
437;
438BEGINPROC PATMTrapEntryErrorCode
439PATMTrapErrorCodeEntryStart:
440 mov dword [ss:PATM_INTERRUPTFLAG], 0
441 pushf
442
443 ; make sure the saved CS selector for ring 1 is made 0
444 test dword [esp+12], 2
445 jnz PATMTrapErrorCodeNoRing1
446 test dword [esp+12], 1
447 jz PATMTrapErrorCodeNoRing1
448 and dword [esp+12], dword ~1 ; yasm / nasm dword
449PATMTrapErrorCodeNoRing1:
450
451 ; correct EFLAGS on the stack to include the current IOPL
452 push eax
453 mov eax, dword [ss:PATM_VMFLAGS]
454 and eax, X86_EFL_IOPL
455 and dword [esp+20], ~X86_EFL_IOPL ; esp+20 = eflags = esp+8+4(efl)+4(error code)+4(eax)
456 or dword [esp+20], eax
457 pop eax
458
459 popf
460 mov dword [ss:PATM_INTERRUPTFLAG], 1
461 DB 0xE9
462PATMTrapErrorCodeEntryJump:
463 DD PATM_JUMPDELTA
464PATMTrapErrorCodeEntryEnd:
465ENDPROC PATMTrapEntryErrorCode
466
467
468; Patch record for trap gate entrypoint
469GLOBALNAME PATMTrapEntryRecordErrorCode
470 RTCCPTR_DEF PATMTrapErrorCodeEntryStart
471 DD PATMTrapErrorCodeEntryJump - PATMTrapErrorCodeEntryStart
472 DD 0
473 DD 0
474 DD PATMTrapErrorCodeEntryEnd - PATMTrapErrorCodeEntryStart
475 DD 3
476 DD PATM_INTERRUPTFLAG
477 DD 0
478 DD PATM_VMFLAGS
479 DD 0
480 DD PATM_INTERRUPTFLAG
481 DD 0
482 DD 0ffffffffh
483
484
485;
486; Trampoline code for interrupt gate entry (without error code on the stack)
487;
488; esp + 16 - SS (if transfer to inner ring)
489; esp + 12 - ESP (if transfer to inner ring)
490; esp + 8 - EFLAGS
491; esp + 4 - CS
492; esp - EIP
493;
494BEGINPROC PATMIntEntry
495PATMIntEntryStart:
496 mov dword [ss:PATM_INTERRUPTFLAG], 0
497 pushf
498
499 ; make sure the saved CS selector for ring 1 is made 0
500 test dword [esp+8], 2
501 jnz PATMIntNoRing1
502 test dword [esp+8], 1
503 jz PATMIntNoRing1
504 and dword [esp+8], dword ~1 ; yasm / nasm dword
505PATMIntNoRing1:
506
507 ; correct EFLAGS on the stack to include the current IOPL
508 push eax
509 mov eax, dword [ss:PATM_VMFLAGS]
510 and eax, X86_EFL_IOPL
511 and dword [esp+16], ~X86_EFL_IOPL ; esp+16 = eflags = esp+8+4(efl)+4(eax)
512 or dword [esp+16], eax
513 pop eax
514
515 popf
516 mov dword [ss:PATM_INTERRUPTFLAG], 1
517PATMIntEntryEnd:
518ENDPROC PATMIntEntry
519
520
521; Patch record for interrupt gate entrypoint
522GLOBALNAME PATMIntEntryRecord
523 RTCCPTR_DEF PATMIntEntryStart
524 DD 0
525 DD 0
526 DD 0
527 DD PATMIntEntryEnd - PATMIntEntryStart
528 DD 3
529 DD PATM_INTERRUPTFLAG
530 DD 0
531 DD PATM_VMFLAGS
532 DD 0
533 DD PATM_INTERRUPTFLAG
534 DD 0
535 DD 0ffffffffh
536
537;
538; Trampoline code for interrupt gate entry (*with* error code on the stack)
539;
540; esp + 20 - SS (if transfer to inner ring)
541; esp + 16 - ESP (if transfer to inner ring)
542; esp + 12 - EFLAGS
543; esp + 8 - CS
544; esp + 4 - EIP
545; esp - error code
546;
547BEGINPROC PATMIntEntryErrorCode
548PATMIntEntryErrorCodeStart:
549 mov dword [ss:PATM_INTERRUPTFLAG], 0
550 pushf
551
552 ; make sure the saved CS selector for ring 1 is made 0
553 test dword [esp+12], 2
554 jnz PATMIntNoRing1_ErrorCode
555 test dword [esp+12], 1
556 jz PATMIntNoRing1_ErrorCode
557 and dword [esp+12], dword ~1 ; yasm / nasm dword
558PATMIntNoRing1_ErrorCode:
559
560 ; correct EFLAGS on the stack to include the current IOPL
561 push eax
562 mov eax, dword [ss:PATM_VMFLAGS]
563 and eax, X86_EFL_IOPL
564 and dword [esp+20], ~X86_EFL_IOPL ; esp+20 = eflags = esp+8+4(efl)+4(eax)+4(error code)
565 or dword [esp+20], eax
566 pop eax
567
568 popf
569 mov dword [ss:PATM_INTERRUPTFLAG], 1
570PATMIntEntryErrorCodeEnd:
571ENDPROC PATMIntEntryErrorCode
572
573
574; Patch record for interrupt gate entrypoint
575GLOBALNAME PATMIntEntryRecordErrorCode
576 RTCCPTR_DEF PATMIntEntryErrorCodeStart
577 DD 0
578 DD 0
579 DD 0
580 DD PATMIntEntryErrorCodeEnd - PATMIntEntryErrorCodeStart
581 DD 3
582 DD PATM_INTERRUPTFLAG
583 DD 0
584 DD PATM_VMFLAGS
585 DD 0
586 DD PATM_INTERRUPTFLAG
587 DD 0
588 DD 0ffffffffh
589
590;
591; 32 bits Popf replacement that faults when IF remains 0
592;
593BEGINPROC PATMPopf32Replacement
594PATMPopf32Start:
595 mov dword [ss:PATM_INTERRUPTFLAG], 0
596%ifdef PATM_LOG_IF_CHANGES
597 push eax
598 push ecx
599 mov eax, PATM_ACTION_LOG_POPF_IF1
600 test dword [esp+8], X86_EFL_IF
601 jnz PATMPopf32_Log
602 mov eax, PATM_ACTION_LOG_POPF_IF0
603
604PATMPopf32_Log:
605 lock or dword [ss:PATM_PENDINGACTION], eax
606 mov ecx, PATM_ACTION_MAGIC
607 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
608 pop ecx
609 pop eax
610%endif
611
612 test dword [esp], X86_EFL_IF
613 jnz PATMPopf32_Ok
614 mov dword [ss:PATM_INTERRUPTFLAG], 1
615 PATM_INT3
616
617PATMPopf32_Ok:
618 pop dword [ss:PATM_VMFLAGS]
619 push dword [ss:PATM_VMFLAGS]
620
621 ; if interrupts are pending, then we must go back to the host context to handle them!
622 test dword [ss:PATM_VM_FORCEDACTIONS], VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_TIMER | VM_FF_REQUEST
623 jz PATMPopf32_Continue
624
625 ; Go to our hypervisor trap handler to dispatch the pending irq
626 mov dword [ss:PATM_TEMP_EAX], eax
627 mov dword [ss:PATM_TEMP_ECX], ecx
628 mov dword [ss:PATM_TEMP_EDI], edi
629 mov dword [ss:PATM_TEMP_RESTORE_FLAGS], PATM_RESTORE_EAX | PATM_RESTORE_ECX | PATM_RESTORE_EDI
630 mov eax, PATM_ACTION_DISPATCH_PENDING_IRQ
631 lock or dword [ss:PATM_PENDINGACTION], eax
632 mov ecx, PATM_ACTION_MAGIC
633 mov edi, PATM_NEXTINSTRADDR
634
635 popfd ; restore flags we pushed above (the or instruction changes the flags as well)
636 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
637 ; does not return
638
639PATMPopf32_Continue:
640 popfd ; restore flags we pushed above
641 mov dword [ss:PATM_INTERRUPTFLAG], 1
642 DB 0xE9
643PATMPopf32Jump:
644 DD PATM_JUMPDELTA
645PATMPopf32End:
646ENDPROC PATMPopf32Replacement
647
648
649; Patch record for 'popfd'
650GLOBALNAME PATMPopf32Record
651 RTCCPTR_DEF PATMPopf32Start
652 DD PATMPopf32Jump - PATMPopf32Start
653 DD 0
654 DD 0
655 DD PATMPopf32End - PATMPopf32Start
656%ifdef PATM_LOG_IF_CHANGES
657 DD 13
658%else
659 DD 12
660%endif
661 DD PATM_INTERRUPTFLAG
662 DD 0
663%ifdef PATM_LOG_IF_CHANGES
664 DD PATM_PENDINGACTION
665 DD 0
666%endif
667 DD PATM_INTERRUPTFLAG
668 DD 0
669 DD PATM_VMFLAGS
670 DD 0
671 DD PATM_VMFLAGS
672 DD 0
673 DD PATM_VM_FORCEDACTIONS
674 DD 0
675 DD PATM_TEMP_EAX
676 DD 0
677 DD PATM_TEMP_ECX
678 DD 0
679 DD PATM_TEMP_EDI
680 DD 0
681 DD PATM_TEMP_RESTORE_FLAGS
682 DD 0
683 DD PATM_PENDINGACTION
684 DD 0
685 DD PATM_NEXTINSTRADDR
686 DD 0
687 DD PATM_INTERRUPTFLAG
688 DD 0
689 DD 0ffffffffh
690
691; no need to check the IF flag when popf isn't an exit point of a patch (e.g. function duplication)
692BEGINPROC PATMPopf32Replacement_NoExit
693PATMPopf32_NoExitStart:
694 mov dword [ss:PATM_INTERRUPTFLAG], 0
695%ifdef PATM_LOG_IF_CHANGES
696 push eax
697 push ecx
698 mov eax, PATM_ACTION_LOG_POPF_IF1
699 test dword [esp+8], X86_EFL_IF
700 jnz PATMPopf32_NoExitLog
701 mov eax, PATM_ACTION_LOG_POPF_IF0
702
703PATMPopf32_NoExitLog:
704 lock or dword [ss:PATM_PENDINGACTION], eax
705 mov ecx, PATM_ACTION_MAGIC
706 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
707 pop ecx
708 pop eax
709%endif
710 test dword [esp], X86_EFL_IF
711 jz PATMPopf32_NoExit_Continue
712
713 ; if interrupts are pending, then we must go back to the host context to handle them!
714 test dword [ss:PATM_VM_FORCEDACTIONS], VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_TIMER | VM_FF_REQUEST
715 jz PATMPopf32_NoExit_Continue
716
717 ; Go to our hypervisor trap handler to dispatch the pending irq
718 mov dword [ss:PATM_TEMP_EAX], eax
719 mov dword [ss:PATM_TEMP_ECX], ecx
720 mov dword [ss:PATM_TEMP_EDI], edi
721 mov dword [ss:PATM_TEMP_RESTORE_FLAGS], PATM_RESTORE_EAX | PATM_RESTORE_ECX | PATM_RESTORE_EDI
722 mov eax, PATM_ACTION_DISPATCH_PENDING_IRQ
723 lock or dword [ss:PATM_PENDINGACTION], eax
724 mov ecx, PATM_ACTION_MAGIC
725 mov edi, PATM_NEXTINSTRADDR
726
727 pop dword [ss:PATM_VMFLAGS] ; restore flags now (the or instruction changes the flags as well)
728 push dword [ss:PATM_VMFLAGS]
729 popfd
730
731 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
732 ; does not return
733
734PATMPopf32_NoExit_Continue:
735 pop dword [ss:PATM_VMFLAGS]
736 push dword [ss:PATM_VMFLAGS]
737 popfd
738 mov dword [ss:PATM_INTERRUPTFLAG], 1
739PATMPopf32_NoExitEnd:
740ENDPROC PATMPopf32Replacement_NoExit
741
742
743; Patch record for 'popfd'
744GLOBALNAME PATMPopf32Record_NoExit
745 RTCCPTR_DEF PATMPopf32_NoExitStart
746 DD 0
747 DD 0
748 DD 0
749 DD PATMPopf32_NoExitEnd - PATMPopf32_NoExitStart
750%ifdef PATM_LOG_IF_CHANGES
751 DD 14
752%else
753 DD 13
754%endif
755 DD PATM_INTERRUPTFLAG
756 DD 0
757%ifdef PATM_LOG_IF_CHANGES
758 DD PATM_PENDINGACTION
759 DD 0
760%endif
761 DD PATM_VM_FORCEDACTIONS
762 DD 0
763 DD PATM_TEMP_EAX
764 DD 0
765 DD PATM_TEMP_ECX
766 DD 0
767 DD PATM_TEMP_EDI
768 DD 0
769 DD PATM_TEMP_RESTORE_FLAGS
770 DD 0
771 DD PATM_PENDINGACTION
772 DD 0
773 DD PATM_NEXTINSTRADDR
774 DD 0
775 DD PATM_VMFLAGS
776 DD 0
777 DD PATM_VMFLAGS
778 DD 0
779 DD PATM_VMFLAGS
780 DD 0
781 DD PATM_VMFLAGS
782 DD 0
783 DD PATM_INTERRUPTFLAG
784 DD 0
785 DD 0ffffffffh
786
787
788;
789; 16 bits Popf replacement that faults when IF remains 0
790;
791BEGINPROC PATMPopf16Replacement
792PATMPopf16Start:
793 mov dword [ss:PATM_INTERRUPTFLAG], 0
794 test word [esp], X86_EFL_IF
795 jnz PATMPopf16_Ok
796 mov dword [ss:PATM_INTERRUPTFLAG], 1
797 PATM_INT3
798
799PATMPopf16_Ok:
800 ; if interrupts are pending, then we must go back to the host context to handle them!
801 ; @note we destroy the flags here, but that should really not matter (PATM_INT3 case)
802 test dword [ss:PATM_VM_FORCEDACTIONS], VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_TIMER | VM_FF_REQUEST
803 jz PATMPopf16_Continue
804 mov dword [ss:PATM_INTERRUPTFLAG], 1
805 PATM_INT3
806
807PATMPopf16_Continue:
808
809 pop word [ss:PATM_VMFLAGS]
810 push word [ss:PATM_VMFLAGS]
811 and dword [ss:PATM_VMFLAGS], PATM_VIRTUAL_FLAGS_MASK
812 or dword [ss:PATM_VMFLAGS], PATM_VIRTUAL_FLAGS_MASK
813
814 DB 0x66 ; size override
815 popf ;after the and and or operations!! (flags must be preserved)
816 mov dword [ss:PATM_INTERRUPTFLAG], 1
817
818 DB 0xE9
819PATMPopf16Jump:
820 DD PATM_JUMPDELTA
821PATMPopf16End:
822ENDPROC PATMPopf16Replacement
823
824
825; Patch record for 'popf'
826GLOBALNAME PATMPopf16Record
827 RTCCPTR_DEF PATMPopf16Start
828 DD PATMPopf16Jump - PATMPopf16Start
829 DD 0
830 DD 0
831 DD PATMPopf16End - PATMPopf16Start
832 DD 9
833 DD PATM_INTERRUPTFLAG
834 DD 0
835 DD PATM_INTERRUPTFLAG
836 DD 0
837 DD PATM_VM_FORCEDACTIONS
838 DD 0
839 DD PATM_INTERRUPTFLAG
840 DD 0
841 DD PATM_VMFLAGS
842 DD 0
843 DD PATM_VMFLAGS
844 DD 0
845 DD PATM_VMFLAGS
846 DD 0
847 DD PATM_VMFLAGS
848 DD 0
849 DD PATM_INTERRUPTFLAG
850 DD 0
851 DD 0ffffffffh
852
853;
854; 16 bits Popf replacement that faults when IF remains 0
855; @todo not necessary to fault in that case (see 32 bits version)
856BEGINPROC PATMPopf16Replacement_NoExit
857PATMPopf16Start_NoExit:
858 mov dword [ss:PATM_INTERRUPTFLAG], 0
859 test word [esp], X86_EFL_IF
860 jnz PATMPopf16_Ok_NoExit
861 mov dword [ss:PATM_INTERRUPTFLAG], 1
862 PATM_INT3
863
864PATMPopf16_Ok_NoExit:
865 ; if interrupts are pending, then we must go back to the host context to handle them!
866 ; @note we destroy the flags here, but that should really not matter (PATM_INT3 case)
867 test dword [ss:PATM_VM_FORCEDACTIONS], VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_TIMER | VM_FF_REQUEST
868 jz PATMPopf16_Continue_NoExit
869 mov dword [ss:PATM_INTERRUPTFLAG], 1
870 PATM_INT3
871
872PATMPopf16_Continue_NoExit:
873
874 pop word [ss:PATM_VMFLAGS]
875 push word [ss:PATM_VMFLAGS]
876 and dword [ss:PATM_VMFLAGS], PATM_VIRTUAL_FLAGS_MASK
877 or dword [ss:PATM_VMFLAGS], PATM_VIRTUAL_FLAGS_MASK
878
879 DB 0x66 ; size override
880 popf ;after the and and or operations!! (flags must be preserved)
881 mov dword [ss:PATM_INTERRUPTFLAG], 1
882PATMPopf16End_NoExit:
883ENDPROC PATMPopf16Replacement_NoExit
884
885
886; Patch record for 'popf'
887GLOBALNAME PATMPopf16Record_NoExit
888 RTCCPTR_DEF PATMPopf16Start_NoExit
889 DD 0
890 DD 0
891 DD 0
892 DD PATMPopf16End_NoExit - PATMPopf16Start_NoExit
893 DD 9
894 DD PATM_INTERRUPTFLAG
895 DD 0
896 DD PATM_INTERRUPTFLAG
897 DD 0
898 DD PATM_VM_FORCEDACTIONS
899 DD 0
900 DD PATM_INTERRUPTFLAG
901 DD 0
902 DD PATM_VMFLAGS
903 DD 0
904 DD PATM_VMFLAGS
905 DD 0
906 DD PATM_VMFLAGS
907 DD 0
908 DD PATM_VMFLAGS
909 DD 0
910 DD PATM_INTERRUPTFLAG
911 DD 0
912 DD 0ffffffffh
913
914
915BEGINPROC PATMPushf32Replacement
916PATMPushf32Start:
917 mov dword [ss:PATM_INTERRUPTFLAG], 0
918 pushfd
919%ifdef PATM_LOG_IF_CHANGES
920 push eax
921 push ecx
922 mov eax, PATM_ACTION_LOG_PUSHF
923 lock or dword [ss:PATM_PENDINGACTION], eax
924 mov ecx, PATM_ACTION_MAGIC
925 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
926 pop ecx
927 pop eax
928%endif
929
930 pushfd
931 push eax
932 mov eax, dword [esp+8]
933 and eax, PATM_FLAGS_MASK
934 or eax, dword [ss:PATM_VMFLAGS]
935 mov dword [esp+8], eax
936 pop eax
937 popfd
938 mov dword [ss:PATM_INTERRUPTFLAG], 1
939PATMPushf32End:
940ENDPROC PATMPushf32Replacement
941
942
943; Patch record for 'pushfd'
944GLOBALNAME PATMPushf32Record
945 RTCCPTR_DEF PATMPushf32Start
946 DD 0
947 DD 0
948 DD 0
949 DD PATMPushf32End - PATMPushf32Start
950%ifdef PATM_LOG_IF_CHANGES
951 DD 4
952%else
953 DD 3
954%endif
955 DD PATM_INTERRUPTFLAG
956 DD 0
957%ifdef PATM_LOG_IF_CHANGES
958 DD PATM_PENDINGACTION
959 DD 0
960%endif
961 DD PATM_VMFLAGS
962 DD 0
963 DD PATM_INTERRUPTFLAG
964 DD 0
965 DD 0ffffffffh
966
967
968BEGINPROC PATMPushf16Replacement
969PATMPushf16Start:
970 mov dword [ss:PATM_INTERRUPTFLAG], 0
971 DB 0x66 ; size override
972 pushf
973 DB 0x66 ; size override
974 pushf
975 push eax
976 xor eax, eax
977 mov ax, word [esp+6]
978 and eax, PATM_FLAGS_MASK
979 or eax, dword [ss:PATM_VMFLAGS]
980 mov word [esp+6], ax
981 pop eax
982
983 DB 0x66 ; size override
984 popf
985 mov dword [ss:PATM_INTERRUPTFLAG], 1
986PATMPushf16End:
987ENDPROC PATMPushf16Replacement
988
989
990; Patch record for 'pushf'
991GLOBALNAME PATMPushf16Record
992 RTCCPTR_DEF PATMPushf16Start
993 DD 0
994 DD 0
995 DD 0
996 DD PATMPushf16End - PATMPushf16Start
997 DD 3
998 DD PATM_INTERRUPTFLAG
999 DD 0
1000 DD PATM_VMFLAGS
1001 DD 0
1002 DD PATM_INTERRUPTFLAG
1003 DD 0
1004 DD 0ffffffffh
1005
1006
1007BEGINPROC PATMPushCSReplacement
1008PATMPushCSStart:
1009 mov dword [ss:PATM_INTERRUPTFLAG], 0
1010 push cs
1011 pushfd
1012
1013 test dword [esp+4], 2
1014 jnz pushcs_notring1
1015
1016 ; change dpl from 1 to 0
1017 and dword [esp+4], dword ~1 ; yasm / nasm dword
1018
1019pushcs_notring1:
1020 popfd
1021
1022 mov dword [ss:PATM_INTERRUPTFLAG], 1
1023 DB 0xE9
1024PATMPushCSJump:
1025 DD PATM_JUMPDELTA
1026PATMPushCSEnd:
1027ENDPROC PATMPushCSReplacement
1028
1029
1030; Patch record for 'push cs'
1031GLOBALNAME PATMPushCSRecord
1032 RTCCPTR_DEF PATMPushCSStart
1033 DD PATMPushCSJump - PATMPushCSStart
1034 DD 0
1035 DD 0
1036 DD PATMPushCSEnd - PATMPushCSStart
1037 DD 2
1038 DD PATM_INTERRUPTFLAG
1039 DD 0
1040 DD PATM_INTERRUPTFLAG
1041 DD 0
1042 DD 0ffffffffh
1043
1044;;****************************************************
1045;; Abstract:
1046;;
1047;; if eflags.NT==0 && iretstack.eflags.VM==0 && iretstack.eflags.IOPL==0
1048;; then
1049;; if return to ring 0 (iretstack.new_cs & 3 == 0)
1050;; then
1051;; if iretstack.new_eflags.IF == 1 && iretstack.new_eflags.IOPL == 0
1052;; then
1053;; iretstack.new_cs |= 1
1054;; else
1055;; int 3
1056;; endif
1057;; uVMFlags &= ~X86_EFL_IF
1058;; iret
1059;; else
1060;; int 3
1061;;****************************************************
1062;;
1063BEGINPROC PATMIretReplacement
1064PATMIretStart:
1065 mov dword [ss:PATM_INTERRUPTFLAG], 0
1066 pushfd
1067
1068%ifdef PATM_LOG_IF_CHANGES
1069 push eax
1070 push ecx
1071 push edx
1072 lea edx, dword [ss:esp+12+4] ;3 dwords + pushed flags -> iret eip
1073 mov eax, PATM_ACTION_LOG_IRET
1074 lock or dword [ss:PATM_PENDINGACTION], eax
1075 mov ecx, PATM_ACTION_MAGIC
1076 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1077 pop edx
1078 pop ecx
1079 pop eax
1080%endif
1081
1082 test dword [esp], X86_EFL_NT
1083 jnz near iret_fault1
1084
1085 test dword [esp+12], X86_EFL_VM
1086 jnz iret_fault
1087
1088 ;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1089 ;;@todo: not correct for iret back to ring 2!!!!!
1090 ;;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1091
1092 test dword [esp+8], 2
1093 jnz iret_notring0
1094
1095 test dword [esp+12], X86_EFL_IF
1096 jz iret_fault
1097
1098 ; if interrupts are pending, then we must go back to the host context to handle them!
1099 ; @@todo fix this properly, so we can dispatch pending interrupts in GC
1100 test dword [ss:PATM_VM_FORCEDACTIONS], VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_TIMER | VM_FF_REQUEST
1101 jz iret_continue
1102
1103 ; Go to our hypervisor trap handler to dispatch the pending irq
1104 mov dword [ss:PATM_TEMP_EAX], eax
1105 mov dword [ss:PATM_TEMP_ECX], ecx
1106 mov dword [ss:PATM_TEMP_EDI], edi
1107 mov dword [ss:PATM_TEMP_RESTORE_FLAGS], PATM_RESTORE_EAX | PATM_RESTORE_ECX | PATM_RESTORE_EDI
1108 mov eax, PATM_ACTION_PENDING_IRQ_AFTER_IRET
1109 lock or dword [ss:PATM_PENDINGACTION], eax
1110 mov ecx, PATM_ACTION_MAGIC
1111 mov edi, PATM_CURINSTRADDR
1112
1113 popfd
1114
1115 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1116 ; does not return
1117
1118iret_continue:
1119 or dword [esp+8], 1
1120iret_notring0:
1121
1122 ; This section must *always* be executed (!!)
1123 ; Extract the IOPL from the return flags, save them to our virtual flags and
1124 ; put them back to zero
1125 push eax
1126 mov eax, dword [esp+16]
1127 and eax, X86_EFL_IOPL
1128 and dword [ss:PATM_VMFLAGS], ~X86_EFL_IOPL
1129 or dword [ss:PATM_VMFLAGS], eax
1130 pop eax
1131 and dword [esp+12], ~X86_EFL_IOPL
1132
1133 ; Set IF again; below we make sure this won't cause problems.
1134 or dword [ss:PATM_VMFLAGS], X86_EFL_IF
1135 popfd
1136
1137 ; make sure iret is executed fully (including the iret below; cli ... iret can otherwise be interrupted)
1138 mov dword [ss:PATM_INHIBITIRQADDR], PATM_CURINSTRADDR
1139 mov dword [ss:PATM_INTERRUPTFLAG], 1
1140 iretd
1141 PATM_INT3
1142
1143iret_fault:
1144 popfd
1145 mov dword [ss:PATM_INTERRUPTFLAG], 1
1146 PATM_INT3
1147
1148iret_fault1:
1149 nop
1150 popfd
1151 mov dword [ss:PATM_INTERRUPTFLAG], 1
1152 PATM_INT3
1153PATMIretEnd:
1154ENDPROC PATMIretReplacement
1155
1156; Patch record for 'iretd'
1157GLOBALNAME PATMIretRecord
1158 RTCCPTR_DEF PATMIretStart
1159 DD 0
1160 DD 0
1161 DD 0
1162 DD PATMIretEnd- PATMIretStart
1163%ifdef PATM_LOG_IF_CHANGES
1164 DD 17
1165%else
1166 DD 16
1167%endif
1168 DD PATM_INTERRUPTFLAG
1169 DD 0
1170%ifdef PATM_LOG_IF_CHANGES
1171 DD PATM_PENDINGACTION
1172 DD 0
1173%endif
1174 DD PATM_VM_FORCEDACTIONS
1175 DD 0
1176 DD PATM_TEMP_EAX
1177 DD 0
1178 DD PATM_TEMP_ECX
1179 DD 0
1180 DD PATM_TEMP_EDI
1181 DD 0
1182 DD PATM_TEMP_RESTORE_FLAGS
1183 DD 0
1184 DD PATM_PENDINGACTION
1185 DD 0
1186 DD PATM_CURINSTRADDR
1187 DD 0
1188 DD PATM_VMFLAGS
1189 DD 0
1190 DD PATM_VMFLAGS
1191 DD 0
1192 DD PATM_VMFLAGS
1193 DD 0
1194 DD PATM_INHIBITIRQADDR
1195 DD 0
1196 DD PATM_CURINSTRADDR
1197 DD 0
1198 DD PATM_INTERRUPTFLAG
1199 DD 0
1200 DD PATM_INTERRUPTFLAG
1201 DD 0
1202 DD PATM_INTERRUPTFLAG
1203 DD 0
1204 DD 0ffffffffh
1205
1206
1207align 16 ; yasm / nasm diff - remove me!
1208BEGINPROC PATMCpuidReplacement
1209PATMCpuidStart:
1210 mov dword [ss:PATM_INTERRUPTFLAG], 0
1211 pushf
1212
1213 cmp eax, PATM_CPUID_STD_MAX
1214 jb short cpuid_std
1215 cmp eax, 0x80000000
1216 jb short cpuid_def
1217 cmp eax, PATM_CPUID_EXT_MAX
1218 jb short cpuid_ext
1219
1220cpuid_def:
1221 mov eax, PATM_CPUID_DEF_PTR
1222 jmp near cpuid_fetch
1223
1224cpuid_std:
1225 mov edx, PATM_CPUID_STD_PTR
1226 jmp cpuid_calc
1227cpuid_ext:
1228 and eax, 0ffh ; strictly speaking not necessary.
1229 mov edx, PATM_CPUID_EXT_PTR
1230cpuid_calc:
1231 lea eax, [ss:eax * 4] ; 4 entries...
1232 lea eax, [ss:eax * 4] ; 4 bytes each
1233 add eax, edx
1234
1235cpuid_fetch:
1236 mov edx, [ss:eax + 12] ; CPUMCPUID layout assumptions!
1237 mov ecx, [ss:eax + 8]
1238 mov ebx, [ss:eax + 4]
1239 mov eax, [ss:eax]
1240
1241 popf
1242 mov dword [ss:PATM_INTERRUPTFLAG], 1
1243
1244PATMCpuidEnd:
1245ENDPROC PATMCpuidReplacement
1246
1247; Patch record for 'cpuid'
1248GLOBALNAME PATMCpuidRecord
1249 RTCCPTR_DEF PATMCpuidStart
1250 DD 0
1251 DD 0
1252 DD 0
1253 DD PATMCpuidEnd- PATMCpuidStart
1254 DD 7
1255 DD PATM_INTERRUPTFLAG
1256 DD 0
1257 DD PATM_CPUID_STD_MAX
1258 DD 0
1259 DD PATM_CPUID_EXT_MAX
1260 DD 0
1261 DD PATM_CPUID_DEF_PTR
1262 DD 0
1263 DD PATM_CPUID_STD_PTR
1264 DD 0
1265 DD PATM_CPUID_EXT_PTR
1266 DD 0
1267 DD PATM_INTERRUPTFLAG
1268 DD 0
1269 DD 0ffffffffh
1270
1271
1272BEGINPROC PATMJEcxReplacement
1273PATMJEcxStart:
1274 mov dword [ss:PATM_INTERRUPTFLAG], 0
1275 pushfd
1276PATMJEcxSizeOverride:
1277 DB 0x90 ; nop
1278 cmp ecx, dword 0 ; yasm / nasm dword
1279 jnz PATMJEcxContinue
1280
1281 popfd
1282 mov dword [ss:PATM_INTERRUPTFLAG], 1
1283 DB 0xE9
1284PATMJEcxJump:
1285 DD PATM_JUMPDELTA
1286
1287PATMJEcxContinue:
1288 popfd
1289 mov dword [ss:PATM_INTERRUPTFLAG], 1
1290PATMJEcxEnd:
1291ENDPROC PATMJEcxReplacement
1292
1293; Patch record for 'JEcx'
1294GLOBALNAME PATMJEcxRecord
1295 RTCCPTR_DEF PATMJEcxStart
1296 DD 0
1297 DD PATMJEcxJump - PATMJEcxStart
1298 DD PATMJEcxSizeOverride - PATMJEcxStart
1299 DD PATMJEcxEnd- PATMJEcxStart
1300 DD 3
1301 DD PATM_INTERRUPTFLAG
1302 DD 0
1303 DD PATM_INTERRUPTFLAG
1304 DD 0
1305 DD PATM_INTERRUPTFLAG
1306 DD 0
1307 DD 0ffffffffh
1308
1309align 16; yasm / nasm diffing. remove me!
1310BEGINPROC PATMLoopReplacement
1311PATMLoopStart:
1312 mov dword [ss:PATM_INTERRUPTFLAG], 0
1313 pushfd
1314PATMLoopSizeOverride:
1315 DB 0x90 ; nop
1316 dec ecx
1317 jz PATMLoopContinue
1318
1319 popfd
1320 mov dword [ss:PATM_INTERRUPTFLAG], 1
1321 DB 0xE9
1322PATMLoopJump:
1323 DD PATM_JUMPDELTA
1324
1325PATMLoopContinue:
1326 popfd
1327 mov dword [ss:PATM_INTERRUPTFLAG], 1
1328PATMLoopEnd:
1329ENDPROC PATMLoopReplacement
1330
1331; Patch record for 'Loop'
1332GLOBALNAME PATMLoopRecord
1333 RTCCPTR_DEF PATMLoopStart
1334 DD 0
1335 DD PATMLoopJump - PATMLoopStart
1336 DD PATMLoopSizeOverride - PATMLoopStart
1337 DD PATMLoopEnd- PATMLoopStart
1338 DD 3
1339 DD PATM_INTERRUPTFLAG
1340 DD 0
1341 DD PATM_INTERRUPTFLAG
1342 DD 0
1343 DD PATM_INTERRUPTFLAG
1344 DD 0
1345 DD 0ffffffffh
1346
1347BEGINPROC PATMLoopZReplacement
1348PATMLoopZStart:
1349 ; jump if ZF=1 AND (E)CX != 0
1350
1351 mov dword [ss:PATM_INTERRUPTFLAG], 0
1352 jnz PATMLoopZEnd
1353 pushfd
1354PATMLoopZSizeOverride:
1355 DB 0x90 ; nop
1356 dec ecx
1357 jz PATMLoopZContinue
1358
1359 popfd
1360 mov dword [ss:PATM_INTERRUPTFLAG], 1
1361 DB 0xE9
1362PATMLoopZJump:
1363 DD PATM_JUMPDELTA
1364
1365PATMLoopZContinue:
1366 popfd
1367 mov dword [ss:PATM_INTERRUPTFLAG], 1
1368PATMLoopZEnd:
1369ENDPROC PATMLoopZReplacement
1370
1371; Patch record for 'Loopz'
1372GLOBALNAME PATMLoopZRecord
1373 RTCCPTR_DEF PATMLoopZStart
1374 DD 0
1375 DD PATMLoopZJump - PATMLoopZStart
1376 DD PATMLoopZSizeOverride - PATMLoopZStart
1377 DD PATMLoopZEnd- PATMLoopZStart
1378 DD 3
1379 DD PATM_INTERRUPTFLAG
1380 DD 0
1381 DD PATM_INTERRUPTFLAG
1382 DD 0
1383 DD PATM_INTERRUPTFLAG
1384 DD 0
1385 DD 0ffffffffh
1386
1387
1388BEGINPROC PATMLoopNZReplacement
1389PATMLoopNZStart:
1390 ; jump if ZF=0 AND (E)CX != 0
1391
1392 mov dword [ss:PATM_INTERRUPTFLAG], 0
1393 jz PATMLoopNZEnd
1394 pushfd
1395PATMLoopNZSizeOverride:
1396 DB 0x90 ; nop
1397 dec ecx
1398 jz PATMLoopNZContinue
1399
1400 popfd
1401 mov dword [ss:PATM_INTERRUPTFLAG], 1
1402 DB 0xE9
1403PATMLoopNZJump:
1404 DD PATM_JUMPDELTA
1405
1406PATMLoopNZContinue:
1407 popfd
1408 mov dword [ss:PATM_INTERRUPTFLAG], 1
1409PATMLoopNZEnd:
1410ENDPROC PATMLoopNZReplacement
1411
1412; Patch record for 'LoopNZ'
1413GLOBALNAME PATMLoopNZRecord
1414 RTCCPTR_DEF PATMLoopNZStart
1415 DD 0
1416 DD PATMLoopNZJump - PATMLoopNZStart
1417 DD PATMLoopNZSizeOverride - PATMLoopNZStart
1418 DD PATMLoopNZEnd- PATMLoopNZStart
1419 DD 3
1420 DD PATM_INTERRUPTFLAG
1421 DD 0
1422 DD PATM_INTERRUPTFLAG
1423 DD 0
1424 DD PATM_INTERRUPTFLAG
1425 DD 0
1426 DD 0ffffffffh
1427
1428align 16
1429; Global patch function for indirect calls
1430; Caller is responsible for clearing PATM_INTERRUPTFLAG and doing:
1431; + 20 push [pTargetGC]
1432; + 16 pushfd
1433; + 12 push [JumpTableAddress]
1434; + 8 push [PATMRelReturnAddress]
1435; + 4 push [GuestReturnAddress]
1436;( + 0 return address )
1437;
1438; @note NEVER change this without bumping the SSM version
1439BEGINPROC PATMLookupAndCall
1440PATMLookupAndCallStart:
1441 push eax
1442 push edx
1443 push edi
1444 push ecx
1445
1446 mov edx, dword [esp+16+20] ; pushed target address
1447
1448 xor eax, eax ; default result -> nothing found
1449 mov edi, dword [esp+16+12] ; jump table
1450 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
1451 cmp ecx, 0
1452 je near PATMLookupAndCall_QueryPATM
1453
1454PATMLookupAndCall_SearchStart:
1455 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
1456 je near PATMLookupAndCall_SearchHit
1457 inc eax
1458 cmp eax, ecx
1459 jl near PATMLookupAndCall_SearchStart
1460
1461PATMLookupAndCall_QueryPATM:
1462 ; nothing found -> let our trap handler try to find it
1463 ; @todo private ugly interface, since we have nothing generic at the moment
1464 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
1465 mov eax, PATM_ACTION_LOOKUP_ADDRESS
1466 mov ecx, PATM_ACTION_MAGIC
1467 ; edx = GC address to find
1468 ; edi = jump table address
1469 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1470
1471 jmp near PATMLookupAndCall_SearchEnd
1472
1473PATMLookupAndCall_Failure:
1474 ; return to caller; it must raise an error, due to patch to guest address translation (remember that there's only one copy of this code block).
1475 pop ecx
1476 pop edi
1477 pop edx
1478 pop eax
1479 ret
1480
1481PATMLookupAndCall_SearchHit:
1482 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
1483
1484 ;@note can be zero, so the next check is required!!
1485
1486PATMLookupAndCall_SearchEnd:
1487 cmp eax, 0
1488 je near PATMLookupAndCall_Failure
1489
1490 mov ecx, eax ; ECX = target address (relative!)
1491 add ecx, PATM_PATCHBASE ; Make it absolute
1492
1493 mov edx, dword PATM_STACKPTR
1494 cmp dword [ss:edx], PATM_STACK_SIZE
1495 ja near PATMLookupAndCall_Failure ; should never happen actually!!!
1496 cmp dword [ss:edx], 0
1497 je near PATMLookupAndCall_Failure ; no more room
1498
1499 ; save the patch return address on our private stack
1500 sub dword [ss:edx], 4 ; sizeof(RTGCPTR)
1501 mov eax, dword PATM_STACKBASE
1502 add eax, dword [ss:edx] ; stack base + stack position
1503 mov edi, dword [esp+16+8] ; PATM return address
1504 mov dword [ss:eax], edi ; relative address of patch return (instruction following this block)
1505
1506 ; save the original return address as well (checked by ret to make sure the guest hasn't messed around with the stack)
1507 mov edi, dword PATM_STACKBASE_GUEST
1508 add edi, dword [ss:edx] ; stack base (guest) + stack position
1509 mov eax, dword [esp+16+4] ; guest return address
1510 mov dword [ss:edi], eax
1511
1512 push ecx ; temporarily store the target address on the stack
1513 add esp, 4
1514 pop ecx
1515 pop edi
1516 pop edx
1517 pop eax
1518 add esp, 24 ; parameters + return address pushed by caller (changes the flags, but that shouldn't matter)
1519 push dword [esp - 20] ; push original guest return address
1520
1521 ; the called function will set PATM_INTERRUPTFLAG (!!)
1522 jmp dword [esp-40] ; call duplicated patch function
1523
1524PATMLookupAndCallEnd:
1525; returning here -> do not add code here or after the jmp!!!!!
1526ENDPROC PATMLookupAndCall
1527
1528; Patch record for indirect calls and jumps
1529GLOBALNAME PATMLookupAndCallRecord
1530 RTCCPTR_DEF PATMLookupAndCallStart
1531 DD 0
1532 DD 0
1533 DD 0
1534 DD PATMLookupAndCallEnd - PATMLookupAndCallStart
1535 DD 5
1536 DD PATM_PENDINGACTION
1537 DD 0
1538 DD PATM_PATCHBASE
1539 DD 0
1540 DD PATM_STACKPTR
1541 DD 0
1542 DD PATM_STACKBASE
1543 DD 0
1544 DD PATM_STACKBASE_GUEST
1545 DD 0
1546 DD 0ffffffffh
1547
1548
1549align 16
1550; Global patch function for indirect jumps
1551; Caller is responsible for clearing PATM_INTERRUPTFLAG and doing:
1552; + 8 push [pTargetGC]
1553; + 4 push [JumpTableAddress]
1554;( + 0 return address )
1555; And saving eflags in PATM_TEMP_EFLAGS
1556;
1557; @note NEVER change this without bumping the SSM version
1558BEGINPROC PATMLookupAndJump
1559PATMLookupAndJumpStart:
1560 push eax
1561 push edx
1562 push edi
1563 push ecx
1564
1565 mov edx, dword [esp+16+8] ; pushed target address
1566
1567 xor eax, eax ; default result -> nothing found
1568 mov edi, dword [esp+16+4] ; jump table
1569 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
1570 cmp ecx, 0
1571 je near PATMLookupAndJump_QueryPATM
1572
1573PATMLookupAndJump_SearchStart:
1574 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
1575 je near PATMLookupAndJump_SearchHit
1576 inc eax
1577 cmp eax, ecx
1578 jl near PATMLookupAndJump_SearchStart
1579
1580PATMLookupAndJump_QueryPATM:
1581 ; nothing found -> let our trap handler try to find it
1582 ; @todo private ugly interface, since we have nothing generic at the moment
1583 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
1584 mov eax, PATM_ACTION_LOOKUP_ADDRESS
1585 mov ecx, PATM_ACTION_MAGIC
1586 ; edx = GC address to find
1587 ; edi = jump table address
1588 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1589
1590 jmp near PATMLookupAndJump_SearchEnd
1591
1592PATMLookupAndJump_Failure:
1593 ; return to caller; it must raise an error, due to patch to guest address translation (remember that there's only one copy of this code block).
1594 pop ecx
1595 pop edi
1596 pop edx
1597 pop eax
1598 ret
1599
1600PATMLookupAndJump_SearchHit:
1601 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
1602
1603 ;@note can be zero, so the next check is required!!
1604
1605PATMLookupAndJump_SearchEnd:
1606 cmp eax, 0
1607 je near PATMLookupAndJump_Failure
1608
1609 mov ecx, eax ; ECX = target address (relative!)
1610 add ecx, PATM_PATCHBASE ; Make it absolute
1611
1612 ; save jump patch target
1613 mov dword [ss:PATM_TEMP_EAX], ecx
1614 pop ecx
1615 pop edi
1616 pop edx
1617 pop eax
1618 add esp, 12 ; parameters + return address pushed by caller
1619 ; restore flags (just to be sure)
1620 push dword [ss:PATM_TEMP_EFLAGS]
1621 popfd
1622
1623 ; the jump destination will set PATM_INTERRUPTFLAG (!!)
1624 jmp dword [ss:PATM_TEMP_EAX] ; call duplicated patch destination address
1625
1626PATMLookupAndJumpEnd:
1627ENDPROC PATMLookupAndJump
1628
1629; Patch record for indirect calls and jumps
1630GLOBALNAME PATMLookupAndJumpRecord
1631 RTCCPTR_DEF PATMLookupAndJumpStart
1632 DD 0
1633 DD 0
1634 DD 0
1635 DD PATMLookupAndJumpEnd - PATMLookupAndJumpStart
1636 DD 5
1637 DD PATM_PENDINGACTION
1638 DD 0
1639 DD PATM_PATCHBASE
1640 DD 0
1641 DD PATM_TEMP_EAX
1642 DD 0
1643 DD PATM_TEMP_EFLAGS
1644 DD 0
1645 DD PATM_TEMP_EAX
1646 DD 0
1647 DD 0ffffffffh
1648
1649
1650
1651
1652align 16
1653; Patch function for static calls
1654; @note static calls have only one lookup slot!
1655; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
1656; push [pTargetGC]
1657;
1658BEGINPROC PATMCall
1659PATMCallStart:
1660 pushfd
1661 push PATM_FIXUP ; fixup for jump table below
1662 push PATM_PATCHNEXTBLOCK
1663 push PATM_RETURNADDR
1664 DB 0E8h ; call
1665 DD PATM_LOOKUP_AND_CALL_FUNCTION
1666 ; we only return in case of a failure
1667 add esp, 12 ; pushed address of jump table
1668 popfd
1669 add esp, 4 ; pushed by caller (changes the flags, but that shouldn't matter (@todo))
1670 mov dword [ss:PATM_INTERRUPTFLAG], 1
1671 PATM_INT3
1672%ifdef DEBUG
1673 ; for disassembly
1674 jmp PATMCallEnd
1675%endif
1676
1677align 4
1678PATMCallTable:
1679 DW 1 ; nrSlots
1680 DW 0 ; ulInsertPos
1681 DD 0 ; cAddresses
1682 RESB PATCHDIRECTJUMPTABLE_SIZE ; only one lookup slot
1683
1684PATMCallEnd:
1685; returning here -> do not add code here or after the jmp!!!!!
1686ENDPROC PATMCall
1687
1688; Patch record for direct calls
1689GLOBALNAME PATMCallRecord
1690 RTCCPTR_DEF PATMCallStart
1691 DD 0
1692 DD 0
1693 DD 0
1694 DD PATMCallEnd - PATMCallStart
1695 DD 5
1696 DD PATM_FIXUP
1697 DD PATMCallTable - PATMCallStart
1698 DD PATM_PATCHNEXTBLOCK
1699 DD 0
1700 DD PATM_RETURNADDR
1701 DD 0
1702 DD PATM_LOOKUP_AND_CALL_FUNCTION
1703 DD 0
1704 DD PATM_INTERRUPTFLAG
1705 DD 0
1706 DD 0ffffffffh
1707
1708
1709align 16
1710; Patch function for indirect calls
1711; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
1712; push [pTargetGC]
1713;
1714BEGINPROC PATMCallIndirect
1715PATMCallIndirectStart:
1716 pushfd
1717 push PATM_FIXUP ; fixup for jump table below
1718 push PATM_PATCHNEXTBLOCK
1719 push PATM_RETURNADDR
1720 DB 0E8h ; call
1721 DD PATM_LOOKUP_AND_CALL_FUNCTION
1722 ; we only return in case of a failure
1723 add esp, 12 ; pushed address of jump table
1724 popfd
1725 add esp, 4 ; pushed by caller (changes the flags, but that shouldn't matter (@todo))
1726 mov dword [ss:PATM_INTERRUPTFLAG], 1
1727 PATM_INT3
1728%ifdef DEBUG
1729 ; for disassembly
1730 jmp PATMCallIndirectEnd
1731%endif
1732
1733align 4
1734PATMCallIndirectTable:
1735 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
1736 DW 0 ; ulInsertPos
1737 DD 0 ; cAddresses
1738 RESB PATCHJUMPTABLE_SIZE ; lookup slots
1739
1740PATMCallIndirectEnd:
1741; returning here -> do not add code here or after the jmp!!!!!
1742ENDPROC PATMCallIndirect
1743
1744; Patch record for indirect calls
1745GLOBALNAME PATMCallIndirectRecord
1746 RTCCPTR_DEF PATMCallIndirectStart
1747 DD 0
1748 DD 0
1749 DD 0
1750 DD PATMCallIndirectEnd - PATMCallIndirectStart
1751 DD 5
1752 DD PATM_FIXUP
1753 DD PATMCallIndirectTable - PATMCallIndirectStart
1754 DD PATM_PATCHNEXTBLOCK
1755 DD 0
1756 DD PATM_RETURNADDR
1757 DD 0
1758 DD PATM_LOOKUP_AND_CALL_FUNCTION
1759 DD 0
1760 DD PATM_INTERRUPTFLAG
1761 DD 0
1762 DD 0ffffffffh
1763
1764
1765align 16
1766; Patch function for indirect jumps
1767; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
1768; push [pTargetGC]
1769;
1770BEGINPROC PATMJumpIndirect
1771PATMJumpIndirectStart:
1772 ; save flags (just to be sure)
1773 pushfd
1774 pop dword [ss:PATM_TEMP_EFLAGS]
1775
1776 push PATM_FIXUP ; fixup for jump table below
1777 DB 0E8h ; call
1778 DD PATM_LOOKUP_AND_JUMP_FUNCTION
1779 ; we only return in case of a failure
1780 add esp, 8 ; pushed address of jump table + pushed target address
1781
1782 ; restore flags (just to be sure)
1783 push dword [ss:PATM_TEMP_EFLAGS]
1784 popfd
1785
1786 mov dword [ss:PATM_INTERRUPTFLAG], 1
1787 PATM_INT3
1788
1789%ifdef DEBUG
1790 ; for disassembly
1791 jmp PATMJumpIndirectEnd
1792%endif
1793
1794align 4
1795PATMJumpIndirectTable:
1796 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
1797 DW 0 ; ulInsertPos
1798 DD 0 ; cAddresses
1799 RESB PATCHJUMPTABLE_SIZE ; lookup slots
1800
1801PATMJumpIndirectEnd:
1802; returning here -> do not add code here or after the jmp!!!!!
1803ENDPROC PATMJumpIndirect
1804
1805; Patch record for indirect jumps
1806GLOBALNAME PATMJumpIndirectRecord
1807 RTCCPTR_DEF PATMJumpIndirectStart
1808 DD 0
1809 DD 0
1810 DD 0
1811 DD PATMJumpIndirectEnd - PATMJumpIndirectStart
1812 DD 5
1813 DD PATM_TEMP_EFLAGS
1814 DD 0
1815 DD PATM_FIXUP
1816 DD PATMJumpIndirectTable - PATMJumpIndirectStart
1817 DD PATM_LOOKUP_AND_JUMP_FUNCTION
1818 DD 0
1819 DD PATM_TEMP_EFLAGS
1820 DD 0
1821 DD PATM_INTERRUPTFLAG
1822 DD 0
1823 DD 0ffffffffh
1824
1825;
1826; return from duplicated function
1827;
1828align 16
1829BEGINPROC PATMRet
1830PATMRet_Start:
1831 ; probe stack here as we can't recover from page faults later on
1832 not dword [esp-32]
1833 not dword [esp-32]
1834 mov dword [ss:PATM_INTERRUPTFLAG], 0
1835 pushfd
1836 push eax
1837 push PATM_FIXUP
1838 DB 0E8h ; call
1839 DD PATM_RETURN_FUNCTION
1840 add esp, 4 ; pushed address of jump table
1841
1842 cmp eax, 0
1843 jne near PATMRet_Success
1844
1845 pop eax
1846 popfd
1847 mov dword [ss:PATM_INTERRUPTFLAG], 1
1848 PATM_INT3
1849
1850%ifdef DEBUG
1851 ; for disassembly
1852 jmp PATMRet_Success
1853%endif
1854align 4
1855PATMRetTable:
1856 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
1857 DW 0 ; ulInsertPos
1858 DD 0 ; cAddresses
1859 RESB PATCHJUMPTABLE_SIZE ; lookup slots
1860
1861PATMRet_Success:
1862 mov dword [esp+8], eax ; overwrite the saved return address
1863 pop eax
1864 popf
1865 ; caller will duplicate the ret or ret n instruction
1866 ; the patched call will set PATM_INTERRUPTFLAG after the return!
1867PATMRet_End:
1868ENDPROC PATMRet
1869
1870GLOBALNAME PATMRetRecord
1871 RTCCPTR_DEF PATMRet_Start
1872 DD 0
1873 DD 0
1874 DD 0
1875 DD PATMRet_End - PATMRet_Start
1876 DD 4
1877 DD PATM_INTERRUPTFLAG
1878 DD 0
1879 DD PATM_FIXUP
1880 DD PATMRetTable - PATMRet_Start
1881 DD PATM_RETURN_FUNCTION
1882 DD 0
1883 DD PATM_INTERRUPTFLAG
1884 DD 0
1885 DD 0ffffffffh
1886
1887;
1888; global function for implementing 'retn'
1889;
1890; Caller is responsible for right stack layout
1891; + 16 original return address
1892; + 12 eflags
1893; + 8 eax
1894; + 4 Jump table address
1895;( + 0 return address )
1896;
1897; @note assumes PATM_INTERRUPTFLAG is zero
1898; @note assumes it can trash eax and eflags
1899;
1900; @returns eax=0 on failure
1901; otherwise return address in eax
1902;
1903; @note NEVER change this without bumping the SSM version
1904align 16
1905BEGINPROC PATMRetFunction
1906PATMRetFunction_Start:
1907 push ecx
1908 push edx
1909 push edi
1910
1911 ; Event order:
1912 ; (@todo figure out which path is taken most often (1 or 2))
1913 ; 1) Check if the return patch address was pushed onto the PATM stack
1914 ; 2) Check if the return patch address can be found in the lookup table
1915 ; 3) Query return patch address from the hypervisor
1916
1917
1918 ; 1) Check if the return patch address was pushed on the PATM stack
1919 cmp dword [ss:PATM_STACKPTR], PATM_STACK_SIZE
1920 jae near PATMRetFunction_FindReturnAddress
1921
1922 mov edx, dword PATM_STACKPTR
1923
1924 ; check if the return address is what we expect it to be
1925 mov eax, dword PATM_STACKBASE_GUEST
1926 add eax, dword [ss:edx] ; stack base + stack position
1927 mov eax, dword [ss:eax] ; original return address
1928 cmp eax, dword [esp+12+16] ; pushed return address
1929
1930 ; the return address was changed -> let our trap handler try to find it
1931 ; (can happen when the guest messes with the stack (seen it) or when we didn't call this function ourselves)
1932 jne near PATMRetFunction_FindReturnAddress
1933
1934 ; found it, convert relative to absolute patch address and return the result to the caller
1935 mov eax, dword PATM_STACKBASE
1936 add eax, dword [ss:edx] ; stack base + stack position
1937 mov eax, dword [ss:eax] ; relative patm return address
1938 add eax, PATM_PATCHBASE
1939
1940%ifdef PATM_LOG_IF_CHANGES
1941 push eax
1942 push ecx
1943 push edx
1944 mov edx, eax ; return address
1945 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_RET
1946 mov eax, PATM_ACTION_LOG_RET
1947 mov ecx, PATM_ACTION_MAGIC
1948 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1949 pop edx
1950 pop ecx
1951 pop eax
1952%endif
1953
1954 add dword [ss:edx], 4 ; pop return address from the PATM stack (sizeof(RTGCPTR); @note hardcoded assumption!)
1955
1956 pop edi
1957 pop edx
1958 pop ecx
1959 ret
1960
1961PATMRetFunction_FindReturnAddress:
1962 ; 2) Check if the return patch address can be found in the lookup table
1963 mov edx, dword [esp+12+16] ; pushed target address
1964
1965 xor eax, eax ; default result -> nothing found
1966 mov edi, dword [esp+12+4] ; jump table
1967 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
1968 cmp ecx, 0
1969 je near PATMRetFunction_AskHypervisor
1970
1971PATMRetFunction_SearchStart:
1972 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
1973 je near PATMRetFunction_SearchHit
1974 inc eax
1975 cmp eax, ecx
1976 jl near PATMRetFunction_SearchStart
1977
1978PATMRetFunction_AskHypervisor:
1979 ; 3) Query return patch address from the hypervisor
1980 ; @todo private ugly interface, since we have nothing generic at the moment
1981 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
1982 mov eax, PATM_ACTION_LOOKUP_ADDRESS
1983 mov ecx, PATM_ACTION_MAGIC
1984 mov edi, dword [esp+12+4] ; jump table address
1985 mov edx, dword [esp+12+16] ; original return address
1986 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1987 jmp near PATMRetFunction_SearchEnd
1988
1989PATMRetFunction_SearchHit:
1990 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
1991 ;@note can be zero, so the next check is required!!
1992
1993PATMRetFunction_SearchEnd:
1994 cmp eax, 0
1995 jz PATMRetFunction_Failure
1996
1997 add eax, PATM_PATCHBASE
1998
1999%ifdef PATM_LOG_IF_CHANGES
2000 push eax
2001 push ecx
2002 push edx
2003 mov edx, eax ; return address
2004 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_RET
2005 mov eax, PATM_ACTION_LOG_RET
2006 mov ecx, PATM_ACTION_MAGIC
2007 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2008 pop edx
2009 pop ecx
2010 pop eax
2011%endif
2012
2013 pop edi
2014 pop edx
2015 pop ecx
2016 ret
2017
2018PATMRetFunction_Failure:
2019 ;signal error
2020 xor eax, eax
2021 pop edi
2022 pop edx
2023 pop ecx
2024 ret
2025
2026PATMRetFunction_End:
2027ENDPROC PATMRetFunction
2028
2029GLOBALNAME PATMRetFunctionRecord
2030 RTCCPTR_DEF PATMRetFunction_Start
2031 DD 0
2032 DD 0
2033 DD 0
2034 DD PATMRetFunction_End - PATMRetFunction_Start
2035%ifdef PATM_LOG_IF_CHANGES
2036 DD 9
2037%else
2038 DD 7
2039%endif
2040 DD PATM_STACKPTR
2041 DD 0
2042 DD PATM_STACKPTR
2043 DD 0
2044 DD PATM_STACKBASE_GUEST
2045 DD 0
2046 DD PATM_STACKBASE
2047 DD 0
2048 DD PATM_PATCHBASE
2049 DD 0
2050%ifdef PATM_LOG_IF_CHANGES
2051 DD PATM_PENDINGACTION
2052 DD 0
2053%endif
2054 DD PATM_PENDINGACTION
2055 DD 0
2056 DD PATM_PATCHBASE
2057 DD 0
2058%ifdef PATM_LOG_IF_CHANGES
2059 DD PATM_PENDINGACTION
2060 DD 0
2061%endif
2062 DD 0ffffffffh
2063
2064
2065;
2066; Jump to original instruction if IF=1
2067;
2068BEGINPROC PATMCheckIF
2069PATMCheckIF_Start:
2070 mov dword [ss:PATM_INTERRUPTFLAG], 0
2071 pushf
2072 test dword [ss:PATM_VMFLAGS], X86_EFL_IF
2073 jnz PATMCheckIF_Safe
2074 nop
2075
2076 ; IF=0 -> unsafe, so we must call the duplicated function (which we don't do here)
2077 popf
2078 mov dword [ss:PATM_INTERRUPTFLAG], 1
2079 jmp PATMCheckIF_End
2080
2081PATMCheckIF_Safe:
2082 ; invalidate the PATM stack as we'll jump back to guest code
2083 mov dword [ss:PATM_STACKPTR], PATM_STACK_SIZE
2084
2085%ifdef PATM_LOG_IF_CHANGES
2086 push eax
2087 push ecx
2088 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_IF1
2089 mov eax, PATM_ACTION_LOG_IF1
2090 mov ecx, PATM_ACTION_MAGIC
2091 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2092 pop ecx
2093 pop eax
2094%endif
2095 popf
2096 mov dword [ss:PATM_INTERRUPTFLAG], 1
2097 ; IF=1 -> we can safely jump back to the original instruction
2098 DB 0xE9
2099PATMCheckIF_Jump:
2100 DD PATM_JUMPDELTA
2101PATMCheckIF_End:
2102ENDPROC PATMCheckIF
2103
2104; Patch record for call instructions
2105GLOBALNAME PATMCheckIFRecord
2106 RTCCPTR_DEF PATMCheckIF_Start
2107 DD PATMCheckIF_Jump - PATMCheckIF_Start
2108 DD 0
2109 DD 0
2110 DD PATMCheckIF_End - PATMCheckIF_Start
2111%ifdef PATM_LOG_IF_CHANGES
2112 DD 6
2113%else
2114 DD 5
2115%endif
2116 DD PATM_INTERRUPTFLAG
2117 DD 0
2118 DD PATM_VMFLAGS
2119 DD 0
2120 DD PATM_INTERRUPTFLAG
2121 DD 0
2122 DD PATM_STACKPTR
2123 DD 0
2124%ifdef PATM_LOG_IF_CHANGES
2125 DD PATM_PENDINGACTION
2126 DD 0
2127%endif
2128 DD PATM_INTERRUPTFLAG
2129 DD 0
2130 DD 0ffffffffh
2131
2132;
2133; Jump back to guest if IF=1, else fault
2134;
2135BEGINPROC PATMJumpToGuest_IF1
2136PATMJumpToGuest_IF1_Start:
2137 mov dword [ss:PATM_INTERRUPTFLAG], 0
2138 pushf
2139 test dword [ss:PATM_VMFLAGS], X86_EFL_IF
2140 jnz PATMJumpToGuest_IF1_Safe
2141 nop
2142
2143 ; IF=0 -> unsafe, so fault
2144 popf
2145 mov dword [ss:PATM_INTERRUPTFLAG], 1
2146 PATM_INT3
2147
2148PATMJumpToGuest_IF1_Safe:
2149 ; IF=1 -> we can safely jump back to the original instruction
2150 popf
2151 mov dword [ss:PATM_INTERRUPTFLAG], 1
2152 DB 0xE9
2153PATMJumpToGuest_IF1_Jump:
2154 DD PATM_JUMPDELTA
2155PATMJumpToGuest_IF1_End:
2156ENDPROC PATMJumpToGuest_IF1
2157
2158; Patch record for call instructions
2159GLOBALNAME PATMJumpToGuest_IF1Record
2160 RTCCPTR_DEF PATMJumpToGuest_IF1_Start
2161 DD PATMJumpToGuest_IF1_Jump - PATMJumpToGuest_IF1_Start
2162 DD 0
2163 DD 0
2164 DD PATMJumpToGuest_IF1_End - PATMJumpToGuest_IF1_Start
2165 DD 4
2166 DD PATM_INTERRUPTFLAG
2167 DD 0
2168 DD PATM_VMFLAGS
2169 DD 0
2170 DD PATM_INTERRUPTFLAG
2171 DD 0
2172 DD PATM_INTERRUPTFLAG
2173 DD 0
2174 DD 0ffffffffh
2175
2176; For assertion during init (to make absolutely sure the flags are in sync in vm.mac & vm.h)
2177GLOBALNAME PATMInterruptFlag
2178 DD VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_TIMER | VM_FF_REQUEST
2179
Note: See TracBrowser for help on using the repository browser.

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