VirtualBox

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

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

We can't do an iret to v86 code, as we run with CPL=1. The iret will attempt a protected mode iret and will (most likely) fault.

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