VirtualBox

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

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

Enabled v86 raw mode again.

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