VirtualBox

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

Last change on this file since 4057 was 4057, checked in by vboxsync, 17 years ago

Don't allow popf instructions to change the current IOPL in simple (cli) patches. (see defect 2042)

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