VirtualBox

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

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

Option to log patch calls

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 64.3 KB
Line 
1; $Id: PATMA.asm 738 2007-02-07 09:44:50Z 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 near 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 near iret_clearIF
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
1153
1154iret_clearIF:
1155 push dword [esp+4] ; eip to return to
1156 pushfd
1157 push eax
1158 push PATM_FIXUP
1159 DB 0E8h ; call
1160 DD PATM_IRET_FUNCTION
1161 add esp, 4 ; pushed address of jump table
1162
1163 cmp eax, 0
1164 je near iret_fault3
1165
1166 mov dword [esp+12+4], eax ; stored eip in iret frame
1167 pop eax
1168 popfd
1169 add esp, 4 ; pushed eip
1170
1171 ; always ring 0 return -> change to ring 1 (CS in iret frame)
1172 or dword [esp+8], 1
1173
1174 ; This section must *always* be executed (!!)
1175 ; Extract the IOPL from the return flags, save them to our virtual flags and
1176 ; put them back to zero
1177 push eax
1178 mov eax, dword [esp+16]
1179 and eax, X86_EFL_IOPL
1180 and dword [ss:PATM_VMFLAGS], ~X86_EFL_IOPL
1181 or dword [ss:PATM_VMFLAGS], eax
1182 pop eax
1183 and dword [esp+12], ~X86_EFL_IOPL
1184
1185 ; Clear IF
1186 and dword [ss:PATM_VMFLAGS], ~X86_EFL_IF
1187 popfd
1188
1189 ; the patched destination code will set PATM_INTERRUPTFLAG after the return!
1190 iretd
1191
1192iret_fault3:
1193 pop eax
1194 popfd
1195 add esp, 4 ; pushed eip
1196 jmp iret_fault
1197
1198align 4
1199PATMIretTable:
1200 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
1201 DW 0 ; ulInsertPos
1202 DD 0 ; cAddresses
1203 RESB PATCHJUMPTABLE_SIZE ; lookup slots
1204
1205PATMIretEnd:
1206ENDPROC PATMIretReplacement
1207
1208; Patch record for 'iretd'
1209GLOBALNAME PATMIretRecord
1210 RTCCPTR_DEF PATMIretStart
1211 DD 0
1212 DD 0
1213 DD 0
1214 DD PATMIretEnd- PATMIretStart
1215%ifdef PATM_LOG_IF_CHANGES
1216 DD 22
1217%else
1218 DD 21
1219%endif
1220 DD PATM_INTERRUPTFLAG
1221 DD 0
1222%ifdef PATM_LOG_IF_CHANGES
1223 DD PATM_PENDINGACTION
1224 DD 0
1225%endif
1226 DD PATM_VM_FORCEDACTIONS
1227 DD 0
1228 DD PATM_TEMP_EAX
1229 DD 0
1230 DD PATM_TEMP_ECX
1231 DD 0
1232 DD PATM_TEMP_EDI
1233 DD 0
1234 DD PATM_TEMP_RESTORE_FLAGS
1235 DD 0
1236 DD PATM_PENDINGACTION
1237 DD 0
1238 DD PATM_CURINSTRADDR
1239 DD 0
1240 DD PATM_VMFLAGS
1241 DD 0
1242 DD PATM_VMFLAGS
1243 DD 0
1244 DD PATM_VMFLAGS
1245 DD 0
1246 DD PATM_INHIBITIRQADDR
1247 DD 0
1248 DD PATM_CURINSTRADDR
1249 DD 0
1250 DD PATM_INTERRUPTFLAG
1251 DD 0
1252 DD PATM_INTERRUPTFLAG
1253 DD 0
1254 DD PATM_INTERRUPTFLAG
1255 DD 0
1256 DD PATM_FIXUP
1257 DD PATMIretTable - PATMIretStart
1258 DD PATM_IRET_FUNCTION
1259 DD 0
1260 DD PATM_VMFLAGS
1261 DD 0
1262 DD PATM_VMFLAGS
1263 DD 0
1264 DD PATM_VMFLAGS
1265 DD 0
1266 DD 0ffffffffh
1267
1268
1269;
1270; global function for implementing 'iret' to code with IF cleared
1271;
1272; Caller is responsible for right stack layout
1273; + 16 original return address
1274; + 12 eflags
1275; + 8 eax
1276; + 4 Jump table address
1277;( + 0 return address )
1278;
1279; @note assumes PATM_INTERRUPTFLAG is zero
1280; @note assumes it can trash eax and eflags
1281;
1282; @returns eax=0 on failure
1283; otherwise return address in eax
1284;
1285; @note NEVER change this without bumping the SSM version
1286align 16
1287BEGINPROC PATMIretFunction
1288PATMIretFunction_Start:
1289 push ecx
1290 push edx
1291 push edi
1292
1293 ; Event order:
1294 ; 1) Check if the return patch address can be found in the lookup table
1295 ; 2) Query return patch address from the hypervisor
1296
1297 ; 1) Check if the return patch address can be found in the lookup table
1298 mov edx, dword [esp+12+16] ; pushed target address
1299
1300 xor eax, eax ; default result -> nothing found
1301 mov edi, dword [esp+12+4] ; jump table
1302 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
1303 cmp ecx, 0
1304 je near PATMIretFunction_AskHypervisor
1305
1306PATMIretFunction_SearchStart:
1307 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
1308 je near PATMIretFunction_SearchHit
1309 inc eax
1310 cmp eax, ecx
1311 jl near PATMIretFunction_SearchStart
1312
1313PATMIretFunction_AskHypervisor:
1314 ; 2) Query return patch address from the hypervisor
1315 ; @todo private ugly interface, since we have nothing generic at the moment
1316 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
1317 mov eax, PATM_ACTION_LOOKUP_ADDRESS
1318 mov ecx, PATM_ACTION_MAGIC
1319 mov edi, dword [esp+12+4] ; jump table address
1320 mov edx, dword [esp+12+16] ; original return address
1321 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1322 jmp near PATMIretFunction_SearchEnd
1323
1324PATMIretFunction_SearchHit:
1325 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
1326 ;@note can be zero, so the next check is required!!
1327
1328PATMIretFunction_SearchEnd:
1329 cmp eax, 0
1330 jz PATMIretFunction_Failure
1331
1332 add eax, PATM_PATCHBASE
1333
1334 pop edi
1335 pop edx
1336 pop ecx
1337 ret
1338
1339PATMIretFunction_Failure:
1340 ;signal error
1341 xor eax, eax
1342 pop edi
1343 pop edx
1344 pop ecx
1345 ret
1346
1347PATMIretFunction_End:
1348ENDPROC PATMIretFunction
1349
1350GLOBALNAME PATMIretFunctionRecord
1351 RTCCPTR_DEF PATMIretFunction_Start
1352 DD 0
1353 DD 0
1354 DD 0
1355 DD PATMIretFunction_End - PATMIretFunction_Start
1356 DD 2
1357 DD PATM_PENDINGACTION
1358 DD 0
1359 DD PATM_PATCHBASE
1360 DD 0
1361 DD 0ffffffffh
1362
1363
1364align 16 ; yasm / nasm diff - remove me!
1365BEGINPROC PATMCpuidReplacement
1366PATMCpuidStart:
1367 mov dword [ss:PATM_INTERRUPTFLAG], 0
1368 pushf
1369
1370 cmp eax, PATM_CPUID_STD_MAX
1371 jb short cpuid_std
1372 cmp eax, 0x80000000
1373 jb short cpuid_def
1374 cmp eax, PATM_CPUID_EXT_MAX
1375 jb short cpuid_ext
1376
1377cpuid_def:
1378 mov eax, PATM_CPUID_DEF_PTR
1379 jmp near cpuid_fetch
1380
1381cpuid_std:
1382 mov edx, PATM_CPUID_STD_PTR
1383 jmp cpuid_calc
1384cpuid_ext:
1385 and eax, 0ffh ; strictly speaking not necessary.
1386 mov edx, PATM_CPUID_EXT_PTR
1387cpuid_calc:
1388 lea eax, [ss:eax * 4] ; 4 entries...
1389 lea eax, [ss:eax * 4] ; 4 bytes each
1390 add eax, edx
1391
1392cpuid_fetch:
1393 mov edx, [ss:eax + 12] ; CPUMCPUID layout assumptions!
1394 mov ecx, [ss:eax + 8]
1395 mov ebx, [ss:eax + 4]
1396 mov eax, [ss:eax]
1397
1398 popf
1399 mov dword [ss:PATM_INTERRUPTFLAG], 1
1400
1401PATMCpuidEnd:
1402ENDPROC PATMCpuidReplacement
1403
1404; Patch record for 'cpuid'
1405GLOBALNAME PATMCpuidRecord
1406 RTCCPTR_DEF PATMCpuidStart
1407 DD 0
1408 DD 0
1409 DD 0
1410 DD PATMCpuidEnd- PATMCpuidStart
1411 DD 7
1412 DD PATM_INTERRUPTFLAG
1413 DD 0
1414 DD PATM_CPUID_STD_MAX
1415 DD 0
1416 DD PATM_CPUID_EXT_MAX
1417 DD 0
1418 DD PATM_CPUID_DEF_PTR
1419 DD 0
1420 DD PATM_CPUID_STD_PTR
1421 DD 0
1422 DD PATM_CPUID_EXT_PTR
1423 DD 0
1424 DD PATM_INTERRUPTFLAG
1425 DD 0
1426 DD 0ffffffffh
1427
1428
1429BEGINPROC PATMJEcxReplacement
1430PATMJEcxStart:
1431 mov dword [ss:PATM_INTERRUPTFLAG], 0
1432 pushfd
1433PATMJEcxSizeOverride:
1434 DB 0x90 ; nop
1435 cmp ecx, dword 0 ; yasm / nasm dword
1436 jnz PATMJEcxContinue
1437
1438 popfd
1439 mov dword [ss:PATM_INTERRUPTFLAG], 1
1440 DB 0xE9
1441PATMJEcxJump:
1442 DD PATM_JUMPDELTA
1443
1444PATMJEcxContinue:
1445 popfd
1446 mov dword [ss:PATM_INTERRUPTFLAG], 1
1447PATMJEcxEnd:
1448ENDPROC PATMJEcxReplacement
1449
1450; Patch record for 'JEcx'
1451GLOBALNAME PATMJEcxRecord
1452 RTCCPTR_DEF PATMJEcxStart
1453 DD 0
1454 DD PATMJEcxJump - PATMJEcxStart
1455 DD PATMJEcxSizeOverride - PATMJEcxStart
1456 DD PATMJEcxEnd- PATMJEcxStart
1457 DD 3
1458 DD PATM_INTERRUPTFLAG
1459 DD 0
1460 DD PATM_INTERRUPTFLAG
1461 DD 0
1462 DD PATM_INTERRUPTFLAG
1463 DD 0
1464 DD 0ffffffffh
1465
1466align 16; yasm / nasm diffing. remove me!
1467BEGINPROC PATMLoopReplacement
1468PATMLoopStart:
1469 mov dword [ss:PATM_INTERRUPTFLAG], 0
1470 pushfd
1471PATMLoopSizeOverride:
1472 DB 0x90 ; nop
1473 dec ecx
1474 jz PATMLoopContinue
1475
1476 popfd
1477 mov dword [ss:PATM_INTERRUPTFLAG], 1
1478 DB 0xE9
1479PATMLoopJump:
1480 DD PATM_JUMPDELTA
1481
1482PATMLoopContinue:
1483 popfd
1484 mov dword [ss:PATM_INTERRUPTFLAG], 1
1485PATMLoopEnd:
1486ENDPROC PATMLoopReplacement
1487
1488; Patch record for 'Loop'
1489GLOBALNAME PATMLoopRecord
1490 RTCCPTR_DEF PATMLoopStart
1491 DD 0
1492 DD PATMLoopJump - PATMLoopStart
1493 DD PATMLoopSizeOverride - PATMLoopStart
1494 DD PATMLoopEnd- PATMLoopStart
1495 DD 3
1496 DD PATM_INTERRUPTFLAG
1497 DD 0
1498 DD PATM_INTERRUPTFLAG
1499 DD 0
1500 DD PATM_INTERRUPTFLAG
1501 DD 0
1502 DD 0ffffffffh
1503
1504BEGINPROC PATMLoopZReplacement
1505PATMLoopZStart:
1506 ; jump if ZF=1 AND (E)CX != 0
1507
1508 mov dword [ss:PATM_INTERRUPTFLAG], 0
1509 jnz PATMLoopZEnd
1510 pushfd
1511PATMLoopZSizeOverride:
1512 DB 0x90 ; nop
1513 dec ecx
1514 jz PATMLoopZContinue
1515
1516 popfd
1517 mov dword [ss:PATM_INTERRUPTFLAG], 1
1518 DB 0xE9
1519PATMLoopZJump:
1520 DD PATM_JUMPDELTA
1521
1522PATMLoopZContinue:
1523 popfd
1524 mov dword [ss:PATM_INTERRUPTFLAG], 1
1525PATMLoopZEnd:
1526ENDPROC PATMLoopZReplacement
1527
1528; Patch record for 'Loopz'
1529GLOBALNAME PATMLoopZRecord
1530 RTCCPTR_DEF PATMLoopZStart
1531 DD 0
1532 DD PATMLoopZJump - PATMLoopZStart
1533 DD PATMLoopZSizeOverride - PATMLoopZStart
1534 DD PATMLoopZEnd- PATMLoopZStart
1535 DD 3
1536 DD PATM_INTERRUPTFLAG
1537 DD 0
1538 DD PATM_INTERRUPTFLAG
1539 DD 0
1540 DD PATM_INTERRUPTFLAG
1541 DD 0
1542 DD 0ffffffffh
1543
1544
1545BEGINPROC PATMLoopNZReplacement
1546PATMLoopNZStart:
1547 ; jump if ZF=0 AND (E)CX != 0
1548
1549 mov dword [ss:PATM_INTERRUPTFLAG], 0
1550 jz PATMLoopNZEnd
1551 pushfd
1552PATMLoopNZSizeOverride:
1553 DB 0x90 ; nop
1554 dec ecx
1555 jz PATMLoopNZContinue
1556
1557 popfd
1558 mov dword [ss:PATM_INTERRUPTFLAG], 1
1559 DB 0xE9
1560PATMLoopNZJump:
1561 DD PATM_JUMPDELTA
1562
1563PATMLoopNZContinue:
1564 popfd
1565 mov dword [ss:PATM_INTERRUPTFLAG], 1
1566PATMLoopNZEnd:
1567ENDPROC PATMLoopNZReplacement
1568
1569; Patch record for 'LoopNZ'
1570GLOBALNAME PATMLoopNZRecord
1571 RTCCPTR_DEF PATMLoopNZStart
1572 DD 0
1573 DD PATMLoopNZJump - PATMLoopNZStart
1574 DD PATMLoopNZSizeOverride - PATMLoopNZStart
1575 DD PATMLoopNZEnd- PATMLoopNZStart
1576 DD 3
1577 DD PATM_INTERRUPTFLAG
1578 DD 0
1579 DD PATM_INTERRUPTFLAG
1580 DD 0
1581 DD PATM_INTERRUPTFLAG
1582 DD 0
1583 DD 0ffffffffh
1584
1585align 16
1586; Global patch function for indirect calls
1587; Caller is responsible for clearing PATM_INTERRUPTFLAG and doing:
1588; + 20 push [pTargetGC]
1589; + 16 pushfd
1590; + 12 push [JumpTableAddress]
1591; + 8 push [PATMRelReturnAddress]
1592; + 4 push [GuestReturnAddress]
1593;( + 0 return address )
1594;
1595; @note NEVER change this without bumping the SSM version
1596BEGINPROC PATMLookupAndCall
1597PATMLookupAndCallStart:
1598 push eax
1599 push edx
1600 push edi
1601 push ecx
1602
1603 mov edx, dword [esp+16+20] ; pushed target address
1604
1605 xor eax, eax ; default result -> nothing found
1606 mov edi, dword [esp+16+12] ; jump table
1607 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
1608 cmp ecx, 0
1609 je near PATMLookupAndCall_QueryPATM
1610
1611PATMLookupAndCall_SearchStart:
1612 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
1613 je near PATMLookupAndCall_SearchHit
1614 inc eax
1615 cmp eax, ecx
1616 jl near PATMLookupAndCall_SearchStart
1617
1618PATMLookupAndCall_QueryPATM:
1619 ; nothing found -> let our trap handler try to find it
1620 ; @todo private ugly interface, since we have nothing generic at the moment
1621 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
1622 mov eax, PATM_ACTION_LOOKUP_ADDRESS
1623 mov ecx, PATM_ACTION_MAGIC
1624 ; edx = GC address to find
1625 ; edi = jump table address
1626 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1627
1628 jmp near PATMLookupAndCall_SearchEnd
1629
1630PATMLookupAndCall_Failure:
1631 ; 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).
1632 pop ecx
1633 pop edi
1634 pop edx
1635 pop eax
1636 ret
1637
1638PATMLookupAndCall_SearchHit:
1639 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
1640
1641 ;@note can be zero, so the next check is required!!
1642
1643PATMLookupAndCall_SearchEnd:
1644 cmp eax, 0
1645 je near PATMLookupAndCall_Failure
1646
1647 mov ecx, eax ; ECX = target address (relative!)
1648 add ecx, PATM_PATCHBASE ; Make it absolute
1649
1650 mov edx, dword PATM_STACKPTR
1651 cmp dword [ss:edx], PATM_STACK_SIZE
1652 ja near PATMLookupAndCall_Failure ; should never happen actually!!!
1653 cmp dword [ss:edx], 0
1654 je near PATMLookupAndCall_Failure ; no more room
1655
1656 ; save the patch return address on our private stack
1657 sub dword [ss:edx], 4 ; sizeof(RTGCPTR)
1658 mov eax, dword PATM_STACKBASE
1659 add eax, dword [ss:edx] ; stack base + stack position
1660 mov edi, dword [esp+16+8] ; PATM return address
1661 mov dword [ss:eax], edi ; relative address of patch return (instruction following this block)
1662
1663 ; save the original return address as well (checked by ret to make sure the guest hasn't messed around with the stack)
1664 mov edi, dword PATM_STACKBASE_GUEST
1665 add edi, dword [ss:edx] ; stack base (guest) + stack position
1666 mov eax, dword [esp+16+4] ; guest return address
1667 mov dword [ss:edi], eax
1668
1669 push ecx ; temporarily store the target address on the stack
1670 add esp, 4
1671 pop ecx
1672 pop edi
1673 pop edx
1674 pop eax
1675 add esp, 24 ; parameters + return address pushed by caller (changes the flags, but that shouldn't matter)
1676
1677%ifdef PATM_LOG_IF_CHANGES
1678 push eax
1679 push ebx
1680 push ecx
1681 push edx
1682 mov ebx, dword [esp - 20 - 16] ; original guest return address
1683 mov edx, dword [esp - 40 + 4 - 16] ; duplicated patch function
1684 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_CALL
1685 mov eax, PATM_ACTION_LOG_RET
1686 mov ecx, PATM_ACTION_MAGIC
1687 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1688 pop edx
1689 pop ecx
1690 pop ebx
1691 pop eax
1692%endif
1693
1694 push dword [esp - 20] ; push original guest return address
1695
1696 ; the called function will set PATM_INTERRUPTFLAG (!!)
1697 jmp dword [esp-40] ; call duplicated patch function
1698
1699PATMLookupAndCallEnd:
1700; returning here -> do not add code here or after the jmp!!!!!
1701ENDPROC PATMLookupAndCall
1702
1703; Patch record for indirect calls and jumps
1704GLOBALNAME PATMLookupAndCallRecord
1705 RTCCPTR_DEF PATMLookupAndCallStart
1706 DD 0
1707 DD 0
1708 DD 0
1709 DD PATMLookupAndCallEnd - PATMLookupAndCallStart
1710%ifdef PATM_LOG_IF_CHANGES
1711 DD 6
1712%else
1713 DD 5
1714%endif
1715 DD PATM_PENDINGACTION
1716 DD 0
1717 DD PATM_PATCHBASE
1718 DD 0
1719 DD PATM_STACKPTR
1720 DD 0
1721 DD PATM_STACKBASE
1722 DD 0
1723 DD PATM_STACKBASE_GUEST
1724 DD 0
1725%ifdef PATM_LOG_IF_CHANGES
1726 DD PATM_PENDINGACTION
1727 DD 0
1728%endif
1729 DD 0ffffffffh
1730
1731
1732align 16
1733; Global patch function for indirect jumps
1734; Caller is responsible for clearing PATM_INTERRUPTFLAG and doing:
1735; + 8 push [pTargetGC]
1736; + 4 push [JumpTableAddress]
1737;( + 0 return address )
1738; And saving eflags in PATM_TEMP_EFLAGS
1739;
1740; @note NEVER change this without bumping the SSM version
1741BEGINPROC PATMLookupAndJump
1742PATMLookupAndJumpStart:
1743 push eax
1744 push edx
1745 push edi
1746 push ecx
1747
1748 mov edx, dword [esp+16+8] ; pushed target address
1749
1750 xor eax, eax ; default result -> nothing found
1751 mov edi, dword [esp+16+4] ; jump table
1752 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
1753 cmp ecx, 0
1754 je near PATMLookupAndJump_QueryPATM
1755
1756PATMLookupAndJump_SearchStart:
1757 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
1758 je near PATMLookupAndJump_SearchHit
1759 inc eax
1760 cmp eax, ecx
1761 jl near PATMLookupAndJump_SearchStart
1762
1763PATMLookupAndJump_QueryPATM:
1764 ; nothing found -> let our trap handler try to find it
1765 ; @todo private ugly interface, since we have nothing generic at the moment
1766 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
1767 mov eax, PATM_ACTION_LOOKUP_ADDRESS
1768 mov ecx, PATM_ACTION_MAGIC
1769 ; edx = GC address to find
1770 ; edi = jump table address
1771 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1772
1773 jmp near PATMLookupAndJump_SearchEnd
1774
1775PATMLookupAndJump_Failure:
1776 ; 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).
1777 pop ecx
1778 pop edi
1779 pop edx
1780 pop eax
1781 ret
1782
1783PATMLookupAndJump_SearchHit:
1784 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
1785
1786 ;@note can be zero, so the next check is required!!
1787
1788PATMLookupAndJump_SearchEnd:
1789 cmp eax, 0
1790 je near PATMLookupAndJump_Failure
1791
1792 mov ecx, eax ; ECX = target address (relative!)
1793 add ecx, PATM_PATCHBASE ; Make it absolute
1794
1795 ; save jump patch target
1796 mov dword [ss:PATM_TEMP_EAX], ecx
1797 pop ecx
1798 pop edi
1799 pop edx
1800 pop eax
1801 add esp, 12 ; parameters + return address pushed by caller
1802 ; restore flags (just to be sure)
1803 push dword [ss:PATM_TEMP_EFLAGS]
1804 popfd
1805
1806 ; the jump destination will set PATM_INTERRUPTFLAG (!!)
1807 jmp dword [ss:PATM_TEMP_EAX] ; call duplicated patch destination address
1808
1809PATMLookupAndJumpEnd:
1810ENDPROC PATMLookupAndJump
1811
1812; Patch record for indirect calls and jumps
1813GLOBALNAME PATMLookupAndJumpRecord
1814 RTCCPTR_DEF PATMLookupAndJumpStart
1815 DD 0
1816 DD 0
1817 DD 0
1818 DD PATMLookupAndJumpEnd - PATMLookupAndJumpStart
1819 DD 5
1820 DD PATM_PENDINGACTION
1821 DD 0
1822 DD PATM_PATCHBASE
1823 DD 0
1824 DD PATM_TEMP_EAX
1825 DD 0
1826 DD PATM_TEMP_EFLAGS
1827 DD 0
1828 DD PATM_TEMP_EAX
1829 DD 0
1830 DD 0ffffffffh
1831
1832
1833
1834
1835align 16
1836; Patch function for static calls
1837; @note static calls have only one lookup slot!
1838; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
1839; push [pTargetGC]
1840;
1841BEGINPROC PATMCall
1842PATMCallStart:
1843 pushfd
1844 push PATM_FIXUP ; fixup for jump table below
1845 push PATM_PATCHNEXTBLOCK
1846 push PATM_RETURNADDR
1847 DB 0E8h ; call
1848 DD PATM_LOOKUP_AND_CALL_FUNCTION
1849 ; we only return in case of a failure
1850 add esp, 12 ; pushed address of jump table
1851 popfd
1852 add esp, 4 ; pushed by caller (changes the flags, but that shouldn't matter (@todo))
1853 mov dword [ss:PATM_INTERRUPTFLAG], 1
1854 PATM_INT3
1855%ifdef DEBUG
1856 ; for disassembly
1857 jmp PATMCallEnd
1858%endif
1859
1860align 4
1861PATMCallTable:
1862 DW 1 ; nrSlots
1863 DW 0 ; ulInsertPos
1864 DD 0 ; cAddresses
1865 RESB PATCHDIRECTJUMPTABLE_SIZE ; only one lookup slot
1866
1867PATMCallEnd:
1868; returning here -> do not add code here or after the jmp!!!!!
1869ENDPROC PATMCall
1870
1871; Patch record for direct calls
1872GLOBALNAME PATMCallRecord
1873 RTCCPTR_DEF PATMCallStart
1874 DD 0
1875 DD 0
1876 DD 0
1877 DD PATMCallEnd - PATMCallStart
1878 DD 5
1879 DD PATM_FIXUP
1880 DD PATMCallTable - PATMCallStart
1881 DD PATM_PATCHNEXTBLOCK
1882 DD 0
1883 DD PATM_RETURNADDR
1884 DD 0
1885 DD PATM_LOOKUP_AND_CALL_FUNCTION
1886 DD 0
1887 DD PATM_INTERRUPTFLAG
1888 DD 0
1889 DD 0ffffffffh
1890
1891
1892align 16
1893; Patch function for indirect calls
1894; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
1895; push [pTargetGC]
1896;
1897BEGINPROC PATMCallIndirect
1898PATMCallIndirectStart:
1899 pushfd
1900 push PATM_FIXUP ; fixup for jump table below
1901 push PATM_PATCHNEXTBLOCK
1902 push PATM_RETURNADDR
1903 DB 0E8h ; call
1904 DD PATM_LOOKUP_AND_CALL_FUNCTION
1905 ; we only return in case of a failure
1906 add esp, 12 ; pushed address of jump table
1907 popfd
1908 add esp, 4 ; pushed by caller (changes the flags, but that shouldn't matter (@todo))
1909 mov dword [ss:PATM_INTERRUPTFLAG], 1
1910 PATM_INT3
1911%ifdef DEBUG
1912 ; for disassembly
1913 jmp PATMCallIndirectEnd
1914%endif
1915
1916align 4
1917PATMCallIndirectTable:
1918 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
1919 DW 0 ; ulInsertPos
1920 DD 0 ; cAddresses
1921 RESB PATCHJUMPTABLE_SIZE ; lookup slots
1922
1923PATMCallIndirectEnd:
1924; returning here -> do not add code here or after the jmp!!!!!
1925ENDPROC PATMCallIndirect
1926
1927; Patch record for indirect calls
1928GLOBALNAME PATMCallIndirectRecord
1929 RTCCPTR_DEF PATMCallIndirectStart
1930 DD 0
1931 DD 0
1932 DD 0
1933 DD PATMCallIndirectEnd - PATMCallIndirectStart
1934 DD 5
1935 DD PATM_FIXUP
1936 DD PATMCallIndirectTable - PATMCallIndirectStart
1937 DD PATM_PATCHNEXTBLOCK
1938 DD 0
1939 DD PATM_RETURNADDR
1940 DD 0
1941 DD PATM_LOOKUP_AND_CALL_FUNCTION
1942 DD 0
1943 DD PATM_INTERRUPTFLAG
1944 DD 0
1945 DD 0ffffffffh
1946
1947
1948align 16
1949; Patch function for indirect jumps
1950; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
1951; push [pTargetGC]
1952;
1953BEGINPROC PATMJumpIndirect
1954PATMJumpIndirectStart:
1955 ; save flags (just to be sure)
1956 pushfd
1957 pop dword [ss:PATM_TEMP_EFLAGS]
1958
1959 push PATM_FIXUP ; fixup for jump table below
1960 DB 0E8h ; call
1961 DD PATM_LOOKUP_AND_JUMP_FUNCTION
1962 ; we only return in case of a failure
1963 add esp, 8 ; pushed address of jump table + pushed target address
1964
1965 ; restore flags (just to be sure)
1966 push dword [ss:PATM_TEMP_EFLAGS]
1967 popfd
1968
1969 mov dword [ss:PATM_INTERRUPTFLAG], 1
1970 PATM_INT3
1971
1972%ifdef DEBUG
1973 ; for disassembly
1974 jmp PATMJumpIndirectEnd
1975%endif
1976
1977align 4
1978PATMJumpIndirectTable:
1979 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
1980 DW 0 ; ulInsertPos
1981 DD 0 ; cAddresses
1982 RESB PATCHJUMPTABLE_SIZE ; lookup slots
1983
1984PATMJumpIndirectEnd:
1985; returning here -> do not add code here or after the jmp!!!!!
1986ENDPROC PATMJumpIndirect
1987
1988; Patch record for indirect jumps
1989GLOBALNAME PATMJumpIndirectRecord
1990 RTCCPTR_DEF PATMJumpIndirectStart
1991 DD 0
1992 DD 0
1993 DD 0
1994 DD PATMJumpIndirectEnd - PATMJumpIndirectStart
1995 DD 5
1996 DD PATM_TEMP_EFLAGS
1997 DD 0
1998 DD PATM_FIXUP
1999 DD PATMJumpIndirectTable - PATMJumpIndirectStart
2000 DD PATM_LOOKUP_AND_JUMP_FUNCTION
2001 DD 0
2002 DD PATM_TEMP_EFLAGS
2003 DD 0
2004 DD PATM_INTERRUPTFLAG
2005 DD 0
2006 DD 0ffffffffh
2007
2008;
2009; return from duplicated function
2010;
2011align 16
2012BEGINPROC PATMRet
2013PATMRet_Start:
2014 ; probe stack here as we can't recover from page faults later on
2015 not dword [esp-32]
2016 not dword [esp-32]
2017 mov dword [ss:PATM_INTERRUPTFLAG], 0
2018 pushfd
2019 push eax
2020 push PATM_FIXUP
2021 DB 0E8h ; call
2022 DD PATM_RETURN_FUNCTION
2023 add esp, 4 ; pushed address of jump table
2024
2025 cmp eax, 0
2026 jne near PATMRet_Success
2027
2028 pop eax
2029 popfd
2030 mov dword [ss:PATM_INTERRUPTFLAG], 1
2031 PATM_INT3
2032
2033%ifdef DEBUG
2034 ; for disassembly
2035 jmp PATMRet_Success
2036%endif
2037align 4
2038PATMRetTable:
2039 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
2040 DW 0 ; ulInsertPos
2041 DD 0 ; cAddresses
2042 RESB PATCHJUMPTABLE_SIZE ; lookup slots
2043
2044PATMRet_Success:
2045 mov dword [esp+8], eax ; overwrite the saved return address
2046 pop eax
2047 popf
2048 ; caller will duplicate the ret or ret n instruction
2049 ; the patched call will set PATM_INTERRUPTFLAG after the return!
2050PATMRet_End:
2051ENDPROC PATMRet
2052
2053GLOBALNAME PATMRetRecord
2054 RTCCPTR_DEF PATMRet_Start
2055 DD 0
2056 DD 0
2057 DD 0
2058 DD PATMRet_End - PATMRet_Start
2059 DD 4
2060 DD PATM_INTERRUPTFLAG
2061 DD 0
2062 DD PATM_FIXUP
2063 DD PATMRetTable - PATMRet_Start
2064 DD PATM_RETURN_FUNCTION
2065 DD 0
2066 DD PATM_INTERRUPTFLAG
2067 DD 0
2068 DD 0ffffffffh
2069
2070;
2071; global function for implementing 'retn'
2072;
2073; Caller is responsible for right stack layout
2074; + 16 original return address
2075; + 12 eflags
2076; + 8 eax
2077; + 4 Jump table address
2078;( + 0 return address )
2079;
2080; @note assumes PATM_INTERRUPTFLAG is zero
2081; @note assumes it can trash eax and eflags
2082;
2083; @returns eax=0 on failure
2084; otherwise return address in eax
2085;
2086; @note NEVER change this without bumping the SSM version
2087align 16
2088BEGINPROC PATMRetFunction
2089PATMRetFunction_Start:
2090 push ecx
2091 push edx
2092 push edi
2093
2094 ; Event order:
2095 ; (@todo figure out which path is taken most often (1 or 2))
2096 ; 1) Check if the return patch address was pushed onto the PATM stack
2097 ; 2) Check if the return patch address can be found in the lookup table
2098 ; 3) Query return patch address from the hypervisor
2099
2100
2101 ; 1) Check if the return patch address was pushed on the PATM stack
2102 cmp dword [ss:PATM_STACKPTR], PATM_STACK_SIZE
2103 jae near PATMRetFunction_FindReturnAddress
2104
2105 mov edx, dword PATM_STACKPTR
2106
2107 ; check if the return address is what we expect it to be
2108 mov eax, dword PATM_STACKBASE_GUEST
2109 add eax, dword [ss:edx] ; stack base + stack position
2110 mov eax, dword [ss:eax] ; original return address
2111 cmp eax, dword [esp+12+16] ; pushed return address
2112
2113 ; the return address was changed -> let our trap handler try to find it
2114 ; (can happen when the guest messes with the stack (seen it) or when we didn't call this function ourselves)
2115 jne near PATMRetFunction_FindReturnAddress
2116
2117 ; found it, convert relative to absolute patch address and return the result to the caller
2118 mov eax, dword PATM_STACKBASE
2119 add eax, dword [ss:edx] ; stack base + stack position
2120 mov eax, dword [ss:eax] ; relative patm return address
2121 add eax, PATM_PATCHBASE
2122
2123%ifdef PATM_LOG_IF_CHANGES
2124 push eax
2125 push ecx
2126 push edx
2127 mov edx, eax ; return address
2128 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_RET
2129 mov eax, PATM_ACTION_LOG_RET
2130 mov ecx, PATM_ACTION_MAGIC
2131 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2132 pop edx
2133 pop ecx
2134 pop eax
2135%endif
2136
2137 add dword [ss:edx], 4 ; pop return address from the PATM stack (sizeof(RTGCPTR); @note hardcoded assumption!)
2138
2139 pop edi
2140 pop edx
2141 pop ecx
2142 ret
2143
2144PATMRetFunction_FindReturnAddress:
2145 ; 2) Check if the return patch address can be found in the lookup table
2146 mov edx, dword [esp+12+16] ; pushed target address
2147
2148 xor eax, eax ; default result -> nothing found
2149 mov edi, dword [esp+12+4] ; jump table
2150 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
2151 cmp ecx, 0
2152 je near PATMRetFunction_AskHypervisor
2153
2154PATMRetFunction_SearchStart:
2155 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
2156 je near PATMRetFunction_SearchHit
2157 inc eax
2158 cmp eax, ecx
2159 jl near PATMRetFunction_SearchStart
2160
2161PATMRetFunction_AskHypervisor:
2162 ; 3) Query return patch address from the hypervisor
2163 ; @todo private ugly interface, since we have nothing generic at the moment
2164 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
2165 mov eax, PATM_ACTION_LOOKUP_ADDRESS
2166 mov ecx, PATM_ACTION_MAGIC
2167 mov edi, dword [esp+12+4] ; jump table address
2168 mov edx, dword [esp+12+16] ; original return address
2169 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2170 jmp near PATMRetFunction_SearchEnd
2171
2172PATMRetFunction_SearchHit:
2173 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
2174 ;@note can be zero, so the next check is required!!
2175
2176PATMRetFunction_SearchEnd:
2177 cmp eax, 0
2178 jz PATMRetFunction_Failure
2179
2180 add eax, PATM_PATCHBASE
2181
2182%ifdef PATM_LOG_IF_CHANGES
2183 push eax
2184 push ecx
2185 push edx
2186 mov edx, eax ; return address
2187 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_RET
2188 mov eax, PATM_ACTION_LOG_RET
2189 mov ecx, PATM_ACTION_MAGIC
2190 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2191 pop edx
2192 pop ecx
2193 pop eax
2194%endif
2195
2196 pop edi
2197 pop edx
2198 pop ecx
2199 ret
2200
2201PATMRetFunction_Failure:
2202 ;signal error
2203 xor eax, eax
2204 pop edi
2205 pop edx
2206 pop ecx
2207 ret
2208
2209PATMRetFunction_End:
2210ENDPROC PATMRetFunction
2211
2212GLOBALNAME PATMRetFunctionRecord
2213 RTCCPTR_DEF PATMRetFunction_Start
2214 DD 0
2215 DD 0
2216 DD 0
2217 DD PATMRetFunction_End - PATMRetFunction_Start
2218%ifdef PATM_LOG_IF_CHANGES
2219 DD 9
2220%else
2221 DD 7
2222%endif
2223 DD PATM_STACKPTR
2224 DD 0
2225 DD PATM_STACKPTR
2226 DD 0
2227 DD PATM_STACKBASE_GUEST
2228 DD 0
2229 DD PATM_STACKBASE
2230 DD 0
2231 DD PATM_PATCHBASE
2232 DD 0
2233%ifdef PATM_LOG_IF_CHANGES
2234 DD PATM_PENDINGACTION
2235 DD 0
2236%endif
2237 DD PATM_PENDINGACTION
2238 DD 0
2239 DD PATM_PATCHBASE
2240 DD 0
2241%ifdef PATM_LOG_IF_CHANGES
2242 DD PATM_PENDINGACTION
2243 DD 0
2244%endif
2245 DD 0ffffffffh
2246
2247
2248;
2249; Jump to original instruction if IF=1
2250;
2251BEGINPROC PATMCheckIF
2252PATMCheckIF_Start:
2253 mov dword [ss:PATM_INTERRUPTFLAG], 0
2254 pushf
2255 test dword [ss:PATM_VMFLAGS], X86_EFL_IF
2256 jnz PATMCheckIF_Safe
2257 nop
2258
2259 ; IF=0 -> unsafe, so we must call the duplicated function (which we don't do here)
2260 popf
2261 mov dword [ss:PATM_INTERRUPTFLAG], 1
2262 jmp PATMCheckIF_End
2263
2264PATMCheckIF_Safe:
2265 ; invalidate the PATM stack as we'll jump back to guest code
2266 mov dword [ss:PATM_STACKPTR], PATM_STACK_SIZE
2267
2268%ifdef PATM_LOG_IF_CHANGES
2269 push eax
2270 push ecx
2271 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_IF1
2272 mov eax, PATM_ACTION_LOG_IF1
2273 mov ecx, PATM_ACTION_MAGIC
2274 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2275 pop ecx
2276 pop eax
2277%endif
2278 popf
2279 mov dword [ss:PATM_INTERRUPTFLAG], 1
2280 ; IF=1 -> we can safely jump back to the original instruction
2281 DB 0xE9
2282PATMCheckIF_Jump:
2283 DD PATM_JUMPDELTA
2284PATMCheckIF_End:
2285ENDPROC PATMCheckIF
2286
2287; Patch record for call instructions
2288GLOBALNAME PATMCheckIFRecord
2289 RTCCPTR_DEF PATMCheckIF_Start
2290 DD PATMCheckIF_Jump - PATMCheckIF_Start
2291 DD 0
2292 DD 0
2293 DD PATMCheckIF_End - PATMCheckIF_Start
2294%ifdef PATM_LOG_IF_CHANGES
2295 DD 6
2296%else
2297 DD 5
2298%endif
2299 DD PATM_INTERRUPTFLAG
2300 DD 0
2301 DD PATM_VMFLAGS
2302 DD 0
2303 DD PATM_INTERRUPTFLAG
2304 DD 0
2305 DD PATM_STACKPTR
2306 DD 0
2307%ifdef PATM_LOG_IF_CHANGES
2308 DD PATM_PENDINGACTION
2309 DD 0
2310%endif
2311 DD PATM_INTERRUPTFLAG
2312 DD 0
2313 DD 0ffffffffh
2314
2315;
2316; Jump back to guest if IF=1, else fault
2317;
2318BEGINPROC PATMJumpToGuest_IF1
2319PATMJumpToGuest_IF1_Start:
2320 mov dword [ss:PATM_INTERRUPTFLAG], 0
2321 pushf
2322 test dword [ss:PATM_VMFLAGS], X86_EFL_IF
2323 jnz PATMJumpToGuest_IF1_Safe
2324 nop
2325
2326 ; IF=0 -> unsafe, so fault
2327 popf
2328 mov dword [ss:PATM_INTERRUPTFLAG], 1
2329 PATM_INT3
2330
2331PATMJumpToGuest_IF1_Safe:
2332 ; IF=1 -> we can safely jump back to the original instruction
2333 popf
2334 mov dword [ss:PATM_INTERRUPTFLAG], 1
2335 DB 0xE9
2336PATMJumpToGuest_IF1_Jump:
2337 DD PATM_JUMPDELTA
2338PATMJumpToGuest_IF1_End:
2339ENDPROC PATMJumpToGuest_IF1
2340
2341; Patch record for call instructions
2342GLOBALNAME PATMJumpToGuest_IF1Record
2343 RTCCPTR_DEF PATMJumpToGuest_IF1_Start
2344 DD PATMJumpToGuest_IF1_Jump - PATMJumpToGuest_IF1_Start
2345 DD 0
2346 DD 0
2347 DD PATMJumpToGuest_IF1_End - PATMJumpToGuest_IF1_Start
2348 DD 4
2349 DD PATM_INTERRUPTFLAG
2350 DD 0
2351 DD PATM_VMFLAGS
2352 DD 0
2353 DD PATM_INTERRUPTFLAG
2354 DD 0
2355 DD PATM_INTERRUPTFLAG
2356 DD 0
2357 DD 0ffffffffh
2358
2359; For assertion during init (to make absolutely sure the flags are in sync in vm.mac & vm.h)
2360GLOBALNAME PATMInterruptFlag
2361 DD VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_TIMER | VM_FF_REQUEST
2362
Note: See TracBrowser for help on using the repository browser.

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