VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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