VirtualBox

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

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

attempt to fix tinderboxes: remove r20142, r20145, r20146

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