VirtualBox

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

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

nasm fix

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