VirtualBox

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

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

Added comment

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