VirtualBox

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

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

Forget it then

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