VirtualBox

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

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

Logging update

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