VirtualBox

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

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

Reenabled raw V86 mode.

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