VirtualBox

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

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

fixed 3 short jumps for nasm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 63.6 KB
Line 
1; $Id: PATMA.asm 396 2007-01-28 01:06:45Z 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 push dword [esp - 20] ; push original guest return address
1677
1678 ; the called function will set PATM_INTERRUPTFLAG (!!)
1679 jmp dword [esp-40] ; call duplicated patch function
1680
1681PATMLookupAndCallEnd:
1682; returning here -> do not add code here or after the jmp!!!!!
1683ENDPROC PATMLookupAndCall
1684
1685; Patch record for indirect calls and jumps
1686GLOBALNAME PATMLookupAndCallRecord
1687 RTCCPTR_DEF PATMLookupAndCallStart
1688 DD 0
1689 DD 0
1690 DD 0
1691 DD PATMLookupAndCallEnd - PATMLookupAndCallStart
1692 DD 5
1693 DD PATM_PENDINGACTION
1694 DD 0
1695 DD PATM_PATCHBASE
1696 DD 0
1697 DD PATM_STACKPTR
1698 DD 0
1699 DD PATM_STACKBASE
1700 DD 0
1701 DD PATM_STACKBASE_GUEST
1702 DD 0
1703 DD 0ffffffffh
1704
1705
1706align 16
1707; Global patch function for indirect jumps
1708; Caller is responsible for clearing PATM_INTERRUPTFLAG and doing:
1709; + 8 push [pTargetGC]
1710; + 4 push [JumpTableAddress]
1711;( + 0 return address )
1712; And saving eflags in PATM_TEMP_EFLAGS
1713;
1714; @note NEVER change this without bumping the SSM version
1715BEGINPROC PATMLookupAndJump
1716PATMLookupAndJumpStart:
1717 push eax
1718 push edx
1719 push edi
1720 push ecx
1721
1722 mov edx, dword [esp+16+8] ; pushed target address
1723
1724 xor eax, eax ; default result -> nothing found
1725 mov edi, dword [esp+16+4] ; jump table
1726 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
1727 cmp ecx, 0
1728 je near PATMLookupAndJump_QueryPATM
1729
1730PATMLookupAndJump_SearchStart:
1731 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
1732 je near PATMLookupAndJump_SearchHit
1733 inc eax
1734 cmp eax, ecx
1735 jl near PATMLookupAndJump_SearchStart
1736
1737PATMLookupAndJump_QueryPATM:
1738 ; nothing found -> let our trap handler try to find it
1739 ; @todo private ugly interface, since we have nothing generic at the moment
1740 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
1741 mov eax, PATM_ACTION_LOOKUP_ADDRESS
1742 mov ecx, PATM_ACTION_MAGIC
1743 ; edx = GC address to find
1744 ; edi = jump table address
1745 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1746
1747 jmp near PATMLookupAndJump_SearchEnd
1748
1749PATMLookupAndJump_Failure:
1750 ; 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).
1751 pop ecx
1752 pop edi
1753 pop edx
1754 pop eax
1755 ret
1756
1757PATMLookupAndJump_SearchHit:
1758 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
1759
1760 ;@note can be zero, so the next check is required!!
1761
1762PATMLookupAndJump_SearchEnd:
1763 cmp eax, 0
1764 je near PATMLookupAndJump_Failure
1765
1766 mov ecx, eax ; ECX = target address (relative!)
1767 add ecx, PATM_PATCHBASE ; Make it absolute
1768
1769 ; save jump patch target
1770 mov dword [ss:PATM_TEMP_EAX], ecx
1771 pop ecx
1772 pop edi
1773 pop edx
1774 pop eax
1775 add esp, 12 ; parameters + return address pushed by caller
1776 ; restore flags (just to be sure)
1777 push dword [ss:PATM_TEMP_EFLAGS]
1778 popfd
1779
1780 ; the jump destination will set PATM_INTERRUPTFLAG (!!)
1781 jmp dword [ss:PATM_TEMP_EAX] ; call duplicated patch destination address
1782
1783PATMLookupAndJumpEnd:
1784ENDPROC PATMLookupAndJump
1785
1786; Patch record for indirect calls and jumps
1787GLOBALNAME PATMLookupAndJumpRecord
1788 RTCCPTR_DEF PATMLookupAndJumpStart
1789 DD 0
1790 DD 0
1791 DD 0
1792 DD PATMLookupAndJumpEnd - PATMLookupAndJumpStart
1793 DD 5
1794 DD PATM_PENDINGACTION
1795 DD 0
1796 DD PATM_PATCHBASE
1797 DD 0
1798 DD PATM_TEMP_EAX
1799 DD 0
1800 DD PATM_TEMP_EFLAGS
1801 DD 0
1802 DD PATM_TEMP_EAX
1803 DD 0
1804 DD 0ffffffffh
1805
1806
1807
1808
1809align 16
1810; Patch function for static calls
1811; @note static calls have only one lookup slot!
1812; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
1813; push [pTargetGC]
1814;
1815BEGINPROC PATMCall
1816PATMCallStart:
1817 pushfd
1818 push PATM_FIXUP ; fixup for jump table below
1819 push PATM_PATCHNEXTBLOCK
1820 push PATM_RETURNADDR
1821 DB 0E8h ; call
1822 DD PATM_LOOKUP_AND_CALL_FUNCTION
1823 ; we only return in case of a failure
1824 add esp, 12 ; pushed address of jump table
1825 popfd
1826 add esp, 4 ; pushed by caller (changes the flags, but that shouldn't matter (@todo))
1827 mov dword [ss:PATM_INTERRUPTFLAG], 1
1828 PATM_INT3
1829%ifdef DEBUG
1830 ; for disassembly
1831 jmp PATMCallEnd
1832%endif
1833
1834align 4
1835PATMCallTable:
1836 DW 1 ; nrSlots
1837 DW 0 ; ulInsertPos
1838 DD 0 ; cAddresses
1839 RESB PATCHDIRECTJUMPTABLE_SIZE ; only one lookup slot
1840
1841PATMCallEnd:
1842; returning here -> do not add code here or after the jmp!!!!!
1843ENDPROC PATMCall
1844
1845; Patch record for direct calls
1846GLOBALNAME PATMCallRecord
1847 RTCCPTR_DEF PATMCallStart
1848 DD 0
1849 DD 0
1850 DD 0
1851 DD PATMCallEnd - PATMCallStart
1852 DD 5
1853 DD PATM_FIXUP
1854 DD PATMCallTable - PATMCallStart
1855 DD PATM_PATCHNEXTBLOCK
1856 DD 0
1857 DD PATM_RETURNADDR
1858 DD 0
1859 DD PATM_LOOKUP_AND_CALL_FUNCTION
1860 DD 0
1861 DD PATM_INTERRUPTFLAG
1862 DD 0
1863 DD 0ffffffffh
1864
1865
1866align 16
1867; Patch function for indirect calls
1868; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
1869; push [pTargetGC]
1870;
1871BEGINPROC PATMCallIndirect
1872PATMCallIndirectStart:
1873 pushfd
1874 push PATM_FIXUP ; fixup for jump table below
1875 push PATM_PATCHNEXTBLOCK
1876 push PATM_RETURNADDR
1877 DB 0E8h ; call
1878 DD PATM_LOOKUP_AND_CALL_FUNCTION
1879 ; we only return in case of a failure
1880 add esp, 12 ; pushed address of jump table
1881 popfd
1882 add esp, 4 ; pushed by caller (changes the flags, but that shouldn't matter (@todo))
1883 mov dword [ss:PATM_INTERRUPTFLAG], 1
1884 PATM_INT3
1885%ifdef DEBUG
1886 ; for disassembly
1887 jmp PATMCallIndirectEnd
1888%endif
1889
1890align 4
1891PATMCallIndirectTable:
1892 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
1893 DW 0 ; ulInsertPos
1894 DD 0 ; cAddresses
1895 RESB PATCHJUMPTABLE_SIZE ; lookup slots
1896
1897PATMCallIndirectEnd:
1898; returning here -> do not add code here or after the jmp!!!!!
1899ENDPROC PATMCallIndirect
1900
1901; Patch record for indirect calls
1902GLOBALNAME PATMCallIndirectRecord
1903 RTCCPTR_DEF PATMCallIndirectStart
1904 DD 0
1905 DD 0
1906 DD 0
1907 DD PATMCallIndirectEnd - PATMCallIndirectStart
1908 DD 5
1909 DD PATM_FIXUP
1910 DD PATMCallIndirectTable - PATMCallIndirectStart
1911 DD PATM_PATCHNEXTBLOCK
1912 DD 0
1913 DD PATM_RETURNADDR
1914 DD 0
1915 DD PATM_LOOKUP_AND_CALL_FUNCTION
1916 DD 0
1917 DD PATM_INTERRUPTFLAG
1918 DD 0
1919 DD 0ffffffffh
1920
1921
1922align 16
1923; Patch function for indirect jumps
1924; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
1925; push [pTargetGC]
1926;
1927BEGINPROC PATMJumpIndirect
1928PATMJumpIndirectStart:
1929 ; save flags (just to be sure)
1930 pushfd
1931 pop dword [ss:PATM_TEMP_EFLAGS]
1932
1933 push PATM_FIXUP ; fixup for jump table below
1934 DB 0E8h ; call
1935 DD PATM_LOOKUP_AND_JUMP_FUNCTION
1936 ; we only return in case of a failure
1937 add esp, 8 ; pushed address of jump table + pushed target address
1938
1939 ; restore flags (just to be sure)
1940 push dword [ss:PATM_TEMP_EFLAGS]
1941 popfd
1942
1943 mov dword [ss:PATM_INTERRUPTFLAG], 1
1944 PATM_INT3
1945
1946%ifdef DEBUG
1947 ; for disassembly
1948 jmp PATMJumpIndirectEnd
1949%endif
1950
1951align 4
1952PATMJumpIndirectTable:
1953 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
1954 DW 0 ; ulInsertPos
1955 DD 0 ; cAddresses
1956 RESB PATCHJUMPTABLE_SIZE ; lookup slots
1957
1958PATMJumpIndirectEnd:
1959; returning here -> do not add code here or after the jmp!!!!!
1960ENDPROC PATMJumpIndirect
1961
1962; Patch record for indirect jumps
1963GLOBALNAME PATMJumpIndirectRecord
1964 RTCCPTR_DEF PATMJumpIndirectStart
1965 DD 0
1966 DD 0
1967 DD 0
1968 DD PATMJumpIndirectEnd - PATMJumpIndirectStart
1969 DD 5
1970 DD PATM_TEMP_EFLAGS
1971 DD 0
1972 DD PATM_FIXUP
1973 DD PATMJumpIndirectTable - PATMJumpIndirectStart
1974 DD PATM_LOOKUP_AND_JUMP_FUNCTION
1975 DD 0
1976 DD PATM_TEMP_EFLAGS
1977 DD 0
1978 DD PATM_INTERRUPTFLAG
1979 DD 0
1980 DD 0ffffffffh
1981
1982;
1983; return from duplicated function
1984;
1985align 16
1986BEGINPROC PATMRet
1987PATMRet_Start:
1988 ; probe stack here as we can't recover from page faults later on
1989 not dword [esp-32]
1990 not dword [esp-32]
1991 mov dword [ss:PATM_INTERRUPTFLAG], 0
1992 pushfd
1993 push eax
1994 push PATM_FIXUP
1995 DB 0E8h ; call
1996 DD PATM_RETURN_FUNCTION
1997 add esp, 4 ; pushed address of jump table
1998
1999 cmp eax, 0
2000 jne near PATMRet_Success
2001
2002 pop eax
2003 popfd
2004 mov dword [ss:PATM_INTERRUPTFLAG], 1
2005 PATM_INT3
2006
2007%ifdef DEBUG
2008 ; for disassembly
2009 jmp PATMRet_Success
2010%endif
2011align 4
2012PATMRetTable:
2013 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
2014 DW 0 ; ulInsertPos
2015 DD 0 ; cAddresses
2016 RESB PATCHJUMPTABLE_SIZE ; lookup slots
2017
2018PATMRet_Success:
2019 mov dword [esp+8], eax ; overwrite the saved return address
2020 pop eax
2021 popf
2022 ; caller will duplicate the ret or ret n instruction
2023 ; the patched call will set PATM_INTERRUPTFLAG after the return!
2024PATMRet_End:
2025ENDPROC PATMRet
2026
2027GLOBALNAME PATMRetRecord
2028 RTCCPTR_DEF PATMRet_Start
2029 DD 0
2030 DD 0
2031 DD 0
2032 DD PATMRet_End - PATMRet_Start
2033 DD 4
2034 DD PATM_INTERRUPTFLAG
2035 DD 0
2036 DD PATM_FIXUP
2037 DD PATMRetTable - PATMRet_Start
2038 DD PATM_RETURN_FUNCTION
2039 DD 0
2040 DD PATM_INTERRUPTFLAG
2041 DD 0
2042 DD 0ffffffffh
2043
2044;
2045; global function for implementing 'retn'
2046;
2047; Caller is responsible for right stack layout
2048; + 16 original return address
2049; + 12 eflags
2050; + 8 eax
2051; + 4 Jump table address
2052;( + 0 return address )
2053;
2054; @note assumes PATM_INTERRUPTFLAG is zero
2055; @note assumes it can trash eax and eflags
2056;
2057; @returns eax=0 on failure
2058; otherwise return address in eax
2059;
2060; @note NEVER change this without bumping the SSM version
2061align 16
2062BEGINPROC PATMRetFunction
2063PATMRetFunction_Start:
2064 push ecx
2065 push edx
2066 push edi
2067
2068 ; Event order:
2069 ; (@todo figure out which path is taken most often (1 or 2))
2070 ; 1) Check if the return patch address was pushed onto the PATM stack
2071 ; 2) Check if the return patch address can be found in the lookup table
2072 ; 3) Query return patch address from the hypervisor
2073
2074
2075 ; 1) Check if the return patch address was pushed on the PATM stack
2076 cmp dword [ss:PATM_STACKPTR], PATM_STACK_SIZE
2077 jae near PATMRetFunction_FindReturnAddress
2078
2079 mov edx, dword PATM_STACKPTR
2080
2081 ; check if the return address is what we expect it to be
2082 mov eax, dword PATM_STACKBASE_GUEST
2083 add eax, dword [ss:edx] ; stack base + stack position
2084 mov eax, dword [ss:eax] ; original return address
2085 cmp eax, dword [esp+12+16] ; pushed return address
2086
2087 ; the return address was changed -> let our trap handler try to find it
2088 ; (can happen when the guest messes with the stack (seen it) or when we didn't call this function ourselves)
2089 jne near PATMRetFunction_FindReturnAddress
2090
2091 ; found it, convert relative to absolute patch address and return the result to the caller
2092 mov eax, dword PATM_STACKBASE
2093 add eax, dword [ss:edx] ; stack base + stack position
2094 mov eax, dword [ss:eax] ; relative patm return address
2095 add eax, PATM_PATCHBASE
2096
2097%ifdef PATM_LOG_IF_CHANGES
2098 push eax
2099 push ecx
2100 push edx
2101 mov edx, eax ; return address
2102 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_RET
2103 mov eax, PATM_ACTION_LOG_RET
2104 mov ecx, PATM_ACTION_MAGIC
2105 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2106 pop edx
2107 pop ecx
2108 pop eax
2109%endif
2110
2111 add dword [ss:edx], 4 ; pop return address from the PATM stack (sizeof(RTGCPTR); @note hardcoded assumption!)
2112
2113 pop edi
2114 pop edx
2115 pop ecx
2116 ret
2117
2118PATMRetFunction_FindReturnAddress:
2119 ; 2) Check if the return patch address can be found in the lookup table
2120 mov edx, dword [esp+12+16] ; pushed target address
2121
2122 xor eax, eax ; default result -> nothing found
2123 mov edi, dword [esp+12+4] ; jump table
2124 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
2125 cmp ecx, 0
2126 je near PATMRetFunction_AskHypervisor
2127
2128PATMRetFunction_SearchStart:
2129 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
2130 je near PATMRetFunction_SearchHit
2131 inc eax
2132 cmp eax, ecx
2133 jl near PATMRetFunction_SearchStart
2134
2135PATMRetFunction_AskHypervisor:
2136 ; 3) Query return patch address from the hypervisor
2137 ; @todo private ugly interface, since we have nothing generic at the moment
2138 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
2139 mov eax, PATM_ACTION_LOOKUP_ADDRESS
2140 mov ecx, PATM_ACTION_MAGIC
2141 mov edi, dword [esp+12+4] ; jump table address
2142 mov edx, dword [esp+12+16] ; original return address
2143 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2144 jmp near PATMRetFunction_SearchEnd
2145
2146PATMRetFunction_SearchHit:
2147 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
2148 ;@note can be zero, so the next check is required!!
2149
2150PATMRetFunction_SearchEnd:
2151 cmp eax, 0
2152 jz PATMRetFunction_Failure
2153
2154 add eax, PATM_PATCHBASE
2155
2156%ifdef PATM_LOG_IF_CHANGES
2157 push eax
2158 push ecx
2159 push edx
2160 mov edx, eax ; return address
2161 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_RET
2162 mov eax, PATM_ACTION_LOG_RET
2163 mov ecx, PATM_ACTION_MAGIC
2164 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2165 pop edx
2166 pop ecx
2167 pop eax
2168%endif
2169
2170 pop edi
2171 pop edx
2172 pop ecx
2173 ret
2174
2175PATMRetFunction_Failure:
2176 ;signal error
2177 xor eax, eax
2178 pop edi
2179 pop edx
2180 pop ecx
2181 ret
2182
2183PATMRetFunction_End:
2184ENDPROC PATMRetFunction
2185
2186GLOBALNAME PATMRetFunctionRecord
2187 RTCCPTR_DEF PATMRetFunction_Start
2188 DD 0
2189 DD 0
2190 DD 0
2191 DD PATMRetFunction_End - PATMRetFunction_Start
2192%ifdef PATM_LOG_IF_CHANGES
2193 DD 9
2194%else
2195 DD 7
2196%endif
2197 DD PATM_STACKPTR
2198 DD 0
2199 DD PATM_STACKPTR
2200 DD 0
2201 DD PATM_STACKBASE_GUEST
2202 DD 0
2203 DD PATM_STACKBASE
2204 DD 0
2205 DD PATM_PATCHBASE
2206 DD 0
2207%ifdef PATM_LOG_IF_CHANGES
2208 DD PATM_PENDINGACTION
2209 DD 0
2210%endif
2211 DD PATM_PENDINGACTION
2212 DD 0
2213 DD PATM_PATCHBASE
2214 DD 0
2215%ifdef PATM_LOG_IF_CHANGES
2216 DD PATM_PENDINGACTION
2217 DD 0
2218%endif
2219 DD 0ffffffffh
2220
2221
2222;
2223; Jump to original instruction if IF=1
2224;
2225BEGINPROC PATMCheckIF
2226PATMCheckIF_Start:
2227 mov dword [ss:PATM_INTERRUPTFLAG], 0
2228 pushf
2229 test dword [ss:PATM_VMFLAGS], X86_EFL_IF
2230 jnz PATMCheckIF_Safe
2231 nop
2232
2233 ; IF=0 -> unsafe, so we must call the duplicated function (which we don't do here)
2234 popf
2235 mov dword [ss:PATM_INTERRUPTFLAG], 1
2236 jmp PATMCheckIF_End
2237
2238PATMCheckIF_Safe:
2239 ; invalidate the PATM stack as we'll jump back to guest code
2240 mov dword [ss:PATM_STACKPTR], PATM_STACK_SIZE
2241
2242%ifdef PATM_LOG_IF_CHANGES
2243 push eax
2244 push ecx
2245 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_IF1
2246 mov eax, PATM_ACTION_LOG_IF1
2247 mov ecx, PATM_ACTION_MAGIC
2248 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2249 pop ecx
2250 pop eax
2251%endif
2252 popf
2253 mov dword [ss:PATM_INTERRUPTFLAG], 1
2254 ; IF=1 -> we can safely jump back to the original instruction
2255 DB 0xE9
2256PATMCheckIF_Jump:
2257 DD PATM_JUMPDELTA
2258PATMCheckIF_End:
2259ENDPROC PATMCheckIF
2260
2261; Patch record for call instructions
2262GLOBALNAME PATMCheckIFRecord
2263 RTCCPTR_DEF PATMCheckIF_Start
2264 DD PATMCheckIF_Jump - PATMCheckIF_Start
2265 DD 0
2266 DD 0
2267 DD PATMCheckIF_End - PATMCheckIF_Start
2268%ifdef PATM_LOG_IF_CHANGES
2269 DD 6
2270%else
2271 DD 5
2272%endif
2273 DD PATM_INTERRUPTFLAG
2274 DD 0
2275 DD PATM_VMFLAGS
2276 DD 0
2277 DD PATM_INTERRUPTFLAG
2278 DD 0
2279 DD PATM_STACKPTR
2280 DD 0
2281%ifdef PATM_LOG_IF_CHANGES
2282 DD PATM_PENDINGACTION
2283 DD 0
2284%endif
2285 DD PATM_INTERRUPTFLAG
2286 DD 0
2287 DD 0ffffffffh
2288
2289;
2290; Jump back to guest if IF=1, else fault
2291;
2292BEGINPROC PATMJumpToGuest_IF1
2293PATMJumpToGuest_IF1_Start:
2294 mov dword [ss:PATM_INTERRUPTFLAG], 0
2295 pushf
2296 test dword [ss:PATM_VMFLAGS], X86_EFL_IF
2297 jnz PATMJumpToGuest_IF1_Safe
2298 nop
2299
2300 ; IF=0 -> unsafe, so fault
2301 popf
2302 mov dword [ss:PATM_INTERRUPTFLAG], 1
2303 PATM_INT3
2304
2305PATMJumpToGuest_IF1_Safe:
2306 ; IF=1 -> we can safely jump back to the original instruction
2307 popf
2308 mov dword [ss:PATM_INTERRUPTFLAG], 1
2309 DB 0xE9
2310PATMJumpToGuest_IF1_Jump:
2311 DD PATM_JUMPDELTA
2312PATMJumpToGuest_IF1_End:
2313ENDPROC PATMJumpToGuest_IF1
2314
2315; Patch record for call instructions
2316GLOBALNAME PATMJumpToGuest_IF1Record
2317 RTCCPTR_DEF PATMJumpToGuest_IF1_Start
2318 DD PATMJumpToGuest_IF1_Jump - PATMJumpToGuest_IF1_Start
2319 DD 0
2320 DD 0
2321 DD PATMJumpToGuest_IF1_End - PATMJumpToGuest_IF1_Start
2322 DD 4
2323 DD PATM_INTERRUPTFLAG
2324 DD 0
2325 DD PATM_VMFLAGS
2326 DD 0
2327 DD PATM_INTERRUPTFLAG
2328 DD 0
2329 DD PATM_INTERRUPTFLAG
2330 DD 0
2331 DD 0ffffffffh
2332
2333; For assertion during init (to make absolutely sure the flags are in sync in vm.mac & vm.h)
2334GLOBALNAME PATMInterruptFlag
2335 DD VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_TIMER | VM_FF_REQUEST
2336
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