VirtualBox

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

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

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