VirtualBox

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

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

deal with the centaur cpuid stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 70.2 KB
Line 
1; $Id: PATMA.asm 5285 2007-10-13 23:55:58Z 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 cmp eax, 0xc0000000
1536 jb cpuid_def
1537 cmp eax, PATM_CPUID_CENTAUR_MAX
1538 jb cpuid_centaur
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
1547
1548cpuid_ext:
1549 and eax, 0ffh ; strictly speaking not necessary.
1550 mov edx, PATM_CPUID_EXT_PTR
1551 jmp cpuid_calc
1552
1553cpuid_centaur:
1554 and eax, 0ffh ; strictly speaking not necessary.
1555 mov edx, PATM_CPUID_CENTAUR_PTR
1556
1557cpuid_calc:
1558 lea eax, [ss:eax * 4] ; 4 entries...
1559 lea eax, [ss:eax * 4] ; 4 bytes each
1560 add eax, edx
1561
1562cpuid_fetch:
1563 mov edx, [ss:eax + 12] ; CPUMCPUID layout assumptions!
1564 mov ecx, [ss:eax + 8]
1565 mov ebx, [ss:eax + 4]
1566 mov eax, [ss:eax]
1567
1568 popf
1569 mov dword [ss:PATM_INTERRUPTFLAG], 1
1570
1571PATMCpuidEnd:
1572ENDPROC PATMCpuidReplacement
1573
1574; Patch record for 'cpuid'
1575GLOBALNAME PATMCpuidRecord
1576 RTCCPTR_DEF PATMCpuidStart
1577 DD 0
1578 DD 0
1579 DD 0
1580 DD PATMCpuidEnd- PATMCpuidStart
1581 DD 7
1582 DD PATM_INTERRUPTFLAG
1583 DD 0
1584 DD PATM_CPUID_STD_MAX
1585 DD 0
1586 DD PATM_CPUID_EXT_MAX
1587 DD 0
1588 DD PATM_CPUID_DEF_PTR
1589 DD 0
1590 DD PATM_CPUID_STD_PTR
1591 DD 0
1592 DD PATM_CPUID_EXT_PTR
1593 DD 0
1594 DD PATM_INTERRUPTFLAG
1595 DD 0
1596 DD 0ffffffffh
1597
1598
1599BEGINPROC PATMJEcxReplacement
1600PATMJEcxStart:
1601 mov dword [ss:PATM_INTERRUPTFLAG], 0
1602 pushfd
1603PATMJEcxSizeOverride:
1604 DB 0x90 ; nop
1605 cmp ecx, dword 0 ; yasm / nasm dword
1606 jnz PATMJEcxContinue
1607
1608 popfd
1609 mov dword [ss:PATM_INTERRUPTFLAG], 1
1610 DB 0xE9
1611PATMJEcxJump:
1612 DD PATM_JUMPDELTA
1613
1614PATMJEcxContinue:
1615 popfd
1616 mov dword [ss:PATM_INTERRUPTFLAG], 1
1617PATMJEcxEnd:
1618ENDPROC PATMJEcxReplacement
1619
1620; Patch record for 'JEcx'
1621GLOBALNAME PATMJEcxRecord
1622 RTCCPTR_DEF PATMJEcxStart
1623 DD 0
1624 DD PATMJEcxJump - PATMJEcxStart
1625 DD PATMJEcxSizeOverride - PATMJEcxStart
1626 DD PATMJEcxEnd- PATMJEcxStart
1627 DD 3
1628 DD PATM_INTERRUPTFLAG
1629 DD 0
1630 DD PATM_INTERRUPTFLAG
1631 DD 0
1632 DD PATM_INTERRUPTFLAG
1633 DD 0
1634 DD 0ffffffffh
1635
1636align 32; yasm / nasm diffing. remove me!
1637BEGINPROC PATMLoopReplacement
1638PATMLoopStart:
1639 mov dword [ss:PATM_INTERRUPTFLAG], 0
1640 pushfd
1641PATMLoopSizeOverride:
1642 DB 0x90 ; nop
1643 dec ecx
1644 jz PATMLoopContinue
1645
1646 popfd
1647 mov dword [ss:PATM_INTERRUPTFLAG], 1
1648 DB 0xE9
1649PATMLoopJump:
1650 DD PATM_JUMPDELTA
1651
1652PATMLoopContinue:
1653 popfd
1654 mov dword [ss:PATM_INTERRUPTFLAG], 1
1655PATMLoopEnd:
1656ENDPROC PATMLoopReplacement
1657
1658; Patch record for 'Loop'
1659GLOBALNAME PATMLoopRecord
1660 RTCCPTR_DEF PATMLoopStart
1661 DD 0
1662 DD PATMLoopJump - PATMLoopStart
1663 DD PATMLoopSizeOverride - PATMLoopStart
1664 DD PATMLoopEnd- PATMLoopStart
1665 DD 3
1666 DD PATM_INTERRUPTFLAG
1667 DD 0
1668 DD PATM_INTERRUPTFLAG
1669 DD 0
1670 DD PATM_INTERRUPTFLAG
1671 DD 0
1672 DD 0ffffffffh
1673
1674BEGINPROC PATMLoopZReplacement
1675PATMLoopZStart:
1676 ; jump if ZF=1 AND (E)CX != 0
1677
1678 mov dword [ss:PATM_INTERRUPTFLAG], 0
1679 jnz PATMLoopZEnd
1680 pushfd
1681PATMLoopZSizeOverride:
1682 DB 0x90 ; nop
1683 dec ecx
1684 jz PATMLoopZContinue
1685
1686 popfd
1687 mov dword [ss:PATM_INTERRUPTFLAG], 1
1688 DB 0xE9
1689PATMLoopZJump:
1690 DD PATM_JUMPDELTA
1691
1692PATMLoopZContinue:
1693 popfd
1694 mov dword [ss:PATM_INTERRUPTFLAG], 1
1695PATMLoopZEnd:
1696ENDPROC PATMLoopZReplacement
1697
1698; Patch record for 'Loopz'
1699GLOBALNAME PATMLoopZRecord
1700 RTCCPTR_DEF PATMLoopZStart
1701 DD 0
1702 DD PATMLoopZJump - PATMLoopZStart
1703 DD PATMLoopZSizeOverride - PATMLoopZStart
1704 DD PATMLoopZEnd- PATMLoopZStart
1705 DD 3
1706 DD PATM_INTERRUPTFLAG
1707 DD 0
1708 DD PATM_INTERRUPTFLAG
1709 DD 0
1710 DD PATM_INTERRUPTFLAG
1711 DD 0
1712 DD 0ffffffffh
1713
1714
1715BEGINPROC PATMLoopNZReplacement
1716PATMLoopNZStart:
1717 ; jump if ZF=0 AND (E)CX != 0
1718
1719 mov dword [ss:PATM_INTERRUPTFLAG], 0
1720 jz PATMLoopNZEnd
1721 pushfd
1722PATMLoopNZSizeOverride:
1723 DB 0x90 ; nop
1724 dec ecx
1725 jz PATMLoopNZContinue
1726
1727 popfd
1728 mov dword [ss:PATM_INTERRUPTFLAG], 1
1729 DB 0xE9
1730PATMLoopNZJump:
1731 DD PATM_JUMPDELTA
1732
1733PATMLoopNZContinue:
1734 popfd
1735 mov dword [ss:PATM_INTERRUPTFLAG], 1
1736PATMLoopNZEnd:
1737ENDPROC PATMLoopNZReplacement
1738
1739; Patch record for 'LoopNZ'
1740GLOBALNAME PATMLoopNZRecord
1741 RTCCPTR_DEF PATMLoopNZStart
1742 DD 0
1743 DD PATMLoopNZJump - PATMLoopNZStart
1744 DD PATMLoopNZSizeOverride - PATMLoopNZStart
1745 DD PATMLoopNZEnd- PATMLoopNZStart
1746 DD 3
1747 DD PATM_INTERRUPTFLAG
1748 DD 0
1749 DD PATM_INTERRUPTFLAG
1750 DD 0
1751 DD PATM_INTERRUPTFLAG
1752 DD 0
1753 DD 0ffffffffh
1754
1755align 32
1756; Global patch function for indirect calls
1757; Caller is responsible for clearing PATM_INTERRUPTFLAG and doing:
1758; + 20 push [pTargetGC]
1759; + 16 pushfd
1760; + 12 push [JumpTableAddress]
1761; + 8 push [PATMRelReturnAddress]
1762; + 4 push [GuestReturnAddress]
1763;( + 0 return address )
1764;
1765; @note NEVER change this without bumping the SSM version
1766BEGINPROC PATMLookupAndCall
1767PATMLookupAndCallStart:
1768 push eax
1769 push edx
1770 push edi
1771 push ecx
1772
1773 mov eax, dword [esp+16+4] ; guest return address
1774 mov dword [ss:PATM_CALL_RETURN_ADDR], eax ; temporary storage
1775
1776 mov edx, dword [esp+16+20] ; pushed target address
1777
1778 xor eax, eax ; default result -> nothing found
1779 mov edi, dword [esp+16+12] ; jump table
1780 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
1781 cmp ecx, 0
1782 je near PATMLookupAndCall_QueryPATM
1783
1784PATMLookupAndCall_SearchStart:
1785 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
1786 je near PATMLookupAndCall_SearchHit
1787 inc eax
1788 cmp eax, ecx
1789 jl near PATMLookupAndCall_SearchStart
1790
1791PATMLookupAndCall_QueryPATM:
1792 ; nothing found -> let our trap handler try to find it
1793 ; @todo private ugly interface, since we have nothing generic at the moment
1794 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
1795 mov eax, PATM_ACTION_LOOKUP_ADDRESS
1796 mov ecx, PATM_ACTION_MAGIC
1797 ; edx = GC address to find
1798 ; edi = jump table address
1799 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1800
1801 jmp near PATMLookupAndCall_SearchEnd
1802
1803PATMLookupAndCall_Failure:
1804 ; 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).
1805 pop ecx
1806 pop edi
1807 pop edx
1808 pop eax
1809 ret
1810
1811PATMLookupAndCall_SearchHit:
1812 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
1813
1814 ;@note can be zero, so the next check is required!!
1815
1816PATMLookupAndCall_SearchEnd:
1817 cmp eax, 0
1818 je near PATMLookupAndCall_Failure
1819
1820 mov ecx, eax ; ECX = target address (relative!)
1821 add ecx, PATM_PATCHBASE ; Make it absolute
1822
1823 mov edx, dword PATM_STACKPTR
1824 cmp dword [ss:edx], PATM_STACK_SIZE
1825 ja near PATMLookupAndCall_Failure ; should never happen actually!!!
1826 cmp dword [ss:edx], 0
1827 je near PATMLookupAndCall_Failure ; no more room
1828
1829 ; save the patch return address on our private stack
1830 sub dword [ss:edx], 4 ; sizeof(RTGCPTR)
1831 mov eax, dword PATM_STACKBASE
1832 add eax, dword [ss:edx] ; stack base + stack position
1833 mov edi, dword [esp+16+8] ; PATM return address
1834 mov dword [ss:eax], edi ; relative address of patch return (instruction following this block)
1835
1836 ; save the original return address as well (checked by ret to make sure the guest hasn't messed around with the stack)
1837 mov edi, dword PATM_STACKBASE_GUEST
1838 add edi, dword [ss:edx] ; stack base (guest) + stack position
1839 mov eax, dword [esp+16+4] ; guest return address
1840 mov dword [ss:edi], eax
1841
1842 mov dword [ss:PATM_CALL_PATCH_TARGET_ADDR], ecx ; temporarily store the target address
1843 pop ecx
1844 pop edi
1845 pop edx
1846 pop eax
1847 add esp, 24 ; parameters + return address pushed by caller (changes the flags, but that shouldn't matter)
1848
1849%ifdef PATM_LOG_PATCHINSTR
1850 push eax
1851 push ecx
1852 push edx
1853 lea edx, [esp + 12 - 4] ; stack address to store return address
1854 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_CALL
1855 mov eax, PATM_ACTION_LOG_CALL
1856 mov ecx, PATM_ACTION_MAGIC
1857 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1858 pop edx
1859 pop ecx
1860 pop eax
1861%endif
1862
1863 push dword [ss:PATM_CALL_RETURN_ADDR] ; push original guest return address
1864
1865 ; the called function will set PATM_INTERRUPTFLAG (!!)
1866 jmp dword [ss:PATM_CALL_PATCH_TARGET_ADDR]
1867
1868PATMLookupAndCallEnd:
1869; returning here -> do not add code here or after the jmp!!!!!
1870ENDPROC PATMLookupAndCall
1871
1872; Patch record for indirect calls and jumps
1873GLOBALNAME PATMLookupAndCallRecord
1874 RTCCPTR_DEF PATMLookupAndCallStart
1875 DD 0
1876 DD 0
1877 DD 0
1878 DD PATMLookupAndCallEnd - PATMLookupAndCallStart
1879%ifdef PATM_LOG_PATCHINSTR
1880 DD 10
1881%else
1882 DD 9
1883%endif
1884 DD PATM_CALL_RETURN_ADDR
1885 DD 0
1886 DD PATM_PENDINGACTION
1887 DD 0
1888 DD PATM_PATCHBASE
1889 DD 0
1890 DD PATM_STACKPTR
1891 DD 0
1892 DD PATM_STACKBASE
1893 DD 0
1894 DD PATM_STACKBASE_GUEST
1895 DD 0
1896 DD PATM_CALL_PATCH_TARGET_ADDR
1897 DD 0
1898%ifdef PATM_LOG_PATCHINSTR
1899 DD PATM_PENDINGACTION
1900 DD 0
1901%endif
1902 DD PATM_CALL_RETURN_ADDR
1903 DD 0
1904 DD PATM_CALL_PATCH_TARGET_ADDR
1905 DD 0
1906 DD 0ffffffffh
1907
1908
1909align 32
1910; Global patch function for indirect jumps
1911; Caller is responsible for clearing PATM_INTERRUPTFLAG and doing:
1912; + 8 push [pTargetGC]
1913; + 4 push [JumpTableAddress]
1914;( + 0 return address )
1915; And saving eflags in PATM_TEMP_EFLAGS
1916;
1917; @note NEVER change this without bumping the SSM version
1918BEGINPROC PATMLookupAndJump
1919PATMLookupAndJumpStart:
1920 push eax
1921 push edx
1922 push edi
1923 push ecx
1924
1925 mov edx, dword [esp+16+8] ; pushed target address
1926
1927 xor eax, eax ; default result -> nothing found
1928 mov edi, dword [esp+16+4] ; jump table
1929 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
1930 cmp ecx, 0
1931 je near PATMLookupAndJump_QueryPATM
1932
1933PATMLookupAndJump_SearchStart:
1934 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
1935 je near PATMLookupAndJump_SearchHit
1936 inc eax
1937 cmp eax, ecx
1938 jl near PATMLookupAndJump_SearchStart
1939
1940PATMLookupAndJump_QueryPATM:
1941 ; nothing found -> let our trap handler try to find it
1942 ; @todo private ugly interface, since we have nothing generic at the moment
1943 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
1944 mov eax, PATM_ACTION_LOOKUP_ADDRESS
1945 mov ecx, PATM_ACTION_MAGIC
1946 ; edx = GC address to find
1947 ; edi = jump table address
1948 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
1949
1950 jmp near PATMLookupAndJump_SearchEnd
1951
1952PATMLookupAndJump_Failure:
1953 ; 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).
1954 pop ecx
1955 pop edi
1956 pop edx
1957 pop eax
1958 ret
1959
1960PATMLookupAndJump_SearchHit:
1961 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
1962
1963 ;@note can be zero, so the next check is required!!
1964
1965PATMLookupAndJump_SearchEnd:
1966 cmp eax, 0
1967 je near PATMLookupAndJump_Failure
1968
1969 mov ecx, eax ; ECX = target address (relative!)
1970 add ecx, PATM_PATCHBASE ; Make it absolute
1971
1972 ; save jump patch target
1973 mov dword [ss:PATM_TEMP_EAX], ecx
1974 pop ecx
1975 pop edi
1976 pop edx
1977 pop eax
1978 add esp, 12 ; parameters + return address pushed by caller
1979 ; restore flags (just to be sure)
1980 push dword [ss:PATM_TEMP_EFLAGS]
1981 popfd
1982
1983 ; the jump destination will set PATM_INTERRUPTFLAG (!!)
1984 jmp dword [ss:PATM_TEMP_EAX] ; call duplicated patch destination address
1985
1986PATMLookupAndJumpEnd:
1987ENDPROC PATMLookupAndJump
1988
1989; Patch record for indirect calls and jumps
1990GLOBALNAME PATMLookupAndJumpRecord
1991 RTCCPTR_DEF PATMLookupAndJumpStart
1992 DD 0
1993 DD 0
1994 DD 0
1995 DD PATMLookupAndJumpEnd - PATMLookupAndJumpStart
1996 DD 5
1997 DD PATM_PENDINGACTION
1998 DD 0
1999 DD PATM_PATCHBASE
2000 DD 0
2001 DD PATM_TEMP_EAX
2002 DD 0
2003 DD PATM_TEMP_EFLAGS
2004 DD 0
2005 DD PATM_TEMP_EAX
2006 DD 0
2007 DD 0ffffffffh
2008
2009
2010
2011
2012align 32
2013; Patch function for static calls
2014; @note static calls have only one lookup slot!
2015; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
2016; push [pTargetGC]
2017;
2018BEGINPROC PATMCall
2019PATMCallStart:
2020 pushfd
2021 push PATM_FIXUP ; fixup for jump table below
2022 push PATM_PATCHNEXTBLOCK
2023 push PATM_RETURNADDR
2024 DB 0E8h ; call
2025 DD PATM_LOOKUP_AND_CALL_FUNCTION
2026 ; we only return in case of a failure
2027 add esp, 12 ; pushed address of jump table
2028 popfd
2029 add esp, 4 ; pushed by caller (changes the flags, but that shouldn't matter (@todo))
2030 mov dword [ss:PATM_INTERRUPTFLAG], 1
2031 PATM_INT3
2032%ifdef DEBUG
2033 ; for disassembly
2034 jmp PATMCallEnd
2035%endif
2036
2037align 4
2038PATMCallTable:
2039 DW 1 ; nrSlots
2040 DW 0 ; ulInsertPos
2041 DD 0 ; cAddresses
2042 TIMES PATCHDIRECTJUMPTABLE_SIZE DB 0 ; only one lookup slot
2043
2044PATMCallEnd:
2045; returning here -> do not add code here or after the jmp!!!!!
2046ENDPROC PATMCall
2047
2048; Patch record for direct calls
2049GLOBALNAME PATMCallRecord
2050 RTCCPTR_DEF PATMCallStart
2051 DD 0
2052 DD 0
2053 DD 0
2054 DD PATMCallEnd - PATMCallStart
2055 DD 5
2056 DD PATM_FIXUP
2057 DD PATMCallTable - PATMCallStart
2058 DD PATM_PATCHNEXTBLOCK
2059 DD 0
2060 DD PATM_RETURNADDR
2061 DD 0
2062 DD PATM_LOOKUP_AND_CALL_FUNCTION
2063 DD 0
2064 DD PATM_INTERRUPTFLAG
2065 DD 0
2066 DD 0ffffffffh
2067
2068
2069align 32
2070; Patch function for indirect calls
2071; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
2072; push [pTargetGC]
2073;
2074BEGINPROC PATMCallIndirect
2075PATMCallIndirectStart:
2076 pushfd
2077 push PATM_FIXUP ; fixup for jump table below
2078 push PATM_PATCHNEXTBLOCK
2079 push PATM_RETURNADDR
2080 DB 0E8h ; call
2081 DD PATM_LOOKUP_AND_CALL_FUNCTION
2082 ; we only return in case of a failure
2083 add esp, 12 ; pushed address of jump table
2084 popfd
2085 add esp, 4 ; pushed by caller (changes the flags, but that shouldn't matter (@todo))
2086 mov dword [ss:PATM_INTERRUPTFLAG], 1
2087 PATM_INT3
2088%ifdef DEBUG
2089 ; for disassembly
2090 jmp PATMCallIndirectEnd
2091%endif
2092
2093align 4
2094PATMCallIndirectTable:
2095 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
2096 DW 0 ; ulInsertPos
2097 DD 0 ; cAddresses
2098 TIMES PATCHJUMPTABLE_SIZE DB 0 ; lookup slots
2099
2100PATMCallIndirectEnd:
2101; returning here -> do not add code here or after the jmp!!!!!
2102ENDPROC PATMCallIndirect
2103
2104; Patch record for indirect calls
2105GLOBALNAME PATMCallIndirectRecord
2106 RTCCPTR_DEF PATMCallIndirectStart
2107 DD 0
2108 DD 0
2109 DD 0
2110 DD PATMCallIndirectEnd - PATMCallIndirectStart
2111 DD 5
2112 DD PATM_FIXUP
2113 DD PATMCallIndirectTable - PATMCallIndirectStart
2114 DD PATM_PATCHNEXTBLOCK
2115 DD 0
2116 DD PATM_RETURNADDR
2117 DD 0
2118 DD PATM_LOOKUP_AND_CALL_FUNCTION
2119 DD 0
2120 DD PATM_INTERRUPTFLAG
2121 DD 0
2122 DD 0ffffffffh
2123
2124
2125align 32
2126; Patch function for indirect jumps
2127; Caller is responsible for clearing PATM_INTERRUPTFLAG and adding:
2128; push [pTargetGC]
2129;
2130BEGINPROC PATMJumpIndirect
2131PATMJumpIndirectStart:
2132 ; save flags (just to be sure)
2133 pushfd
2134 pop dword [ss:PATM_TEMP_EFLAGS]
2135
2136 push PATM_FIXUP ; fixup for jump table below
2137 DB 0E8h ; call
2138 DD PATM_LOOKUP_AND_JUMP_FUNCTION
2139 ; we only return in case of a failure
2140 add esp, 8 ; pushed address of jump table + pushed target address
2141
2142 ; restore flags (just to be sure)
2143 push dword [ss:PATM_TEMP_EFLAGS]
2144 popfd
2145
2146 mov dword [ss:PATM_INTERRUPTFLAG], 1
2147 PATM_INT3
2148
2149%ifdef DEBUG
2150 ; for disassembly
2151 jmp PATMJumpIndirectEnd
2152%endif
2153
2154align 4
2155PATMJumpIndirectTable:
2156 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
2157 DW 0 ; ulInsertPos
2158 DD 0 ; cAddresses
2159 TIMES PATCHJUMPTABLE_SIZE DB 0 ; lookup slots
2160
2161PATMJumpIndirectEnd:
2162; returning here -> do not add code here or after the jmp!!!!!
2163ENDPROC PATMJumpIndirect
2164
2165; Patch record for indirect jumps
2166GLOBALNAME PATMJumpIndirectRecord
2167 RTCCPTR_DEF PATMJumpIndirectStart
2168 DD 0
2169 DD 0
2170 DD 0
2171 DD PATMJumpIndirectEnd - PATMJumpIndirectStart
2172 DD 5
2173 DD PATM_TEMP_EFLAGS
2174 DD 0
2175 DD PATM_FIXUP
2176 DD PATMJumpIndirectTable - PATMJumpIndirectStart
2177 DD PATM_LOOKUP_AND_JUMP_FUNCTION
2178 DD 0
2179 DD PATM_TEMP_EFLAGS
2180 DD 0
2181 DD PATM_INTERRUPTFLAG
2182 DD 0
2183 DD 0ffffffffh
2184
2185;
2186; return from duplicated function
2187;
2188align 32
2189BEGINPROC PATMRet
2190PATMRet_Start:
2191 ; probe stack here as we can't recover from page faults later on
2192 not dword [esp-32]
2193 not dword [esp-32]
2194 mov dword [ss:PATM_INTERRUPTFLAG], 0
2195 pushfd
2196 push eax
2197 push PATM_FIXUP
2198 DB 0E8h ; call
2199 DD PATM_RETURN_FUNCTION
2200 add esp, 4 ; pushed address of jump table
2201
2202 cmp eax, 0
2203 jne near PATMRet_Success
2204
2205 pop eax
2206 popfd
2207 mov dword [ss:PATM_INTERRUPTFLAG], 1
2208 PATM_INT3
2209
2210%ifdef DEBUG
2211 ; for disassembly
2212 jmp PATMRet_Success
2213%endif
2214align 4
2215PATMRetTable:
2216 DW PATM_MAX_JUMPTABLE_ENTRIES ; nrSlots
2217 DW 0 ; ulInsertPos
2218 DD 0 ; cAddresses
2219 TIMES PATCHJUMPTABLE_SIZE DB 0 ; lookup slots
2220
2221PATMRet_Success:
2222 mov dword [esp+8], eax ; overwrite the saved return address
2223 pop eax
2224 popf
2225 ; caller will duplicate the ret or ret n instruction
2226 ; the patched call will set PATM_INTERRUPTFLAG after the return!
2227PATMRet_End:
2228ENDPROC PATMRet
2229
2230GLOBALNAME PATMRetRecord
2231 RTCCPTR_DEF PATMRet_Start
2232 DD 0
2233 DD 0
2234 DD 0
2235 DD PATMRet_End - PATMRet_Start
2236 DD 4
2237 DD PATM_INTERRUPTFLAG
2238 DD 0
2239 DD PATM_FIXUP
2240 DD PATMRetTable - PATMRet_Start
2241 DD PATM_RETURN_FUNCTION
2242 DD 0
2243 DD PATM_INTERRUPTFLAG
2244 DD 0
2245 DD 0ffffffffh
2246
2247;
2248; global function for implementing 'retn'
2249;
2250; Caller is responsible for right stack layout
2251; + 16 original return address
2252; + 12 eflags
2253; + 8 eax
2254; + 4 Jump table address
2255;( + 0 return address )
2256;
2257; @note assumes PATM_INTERRUPTFLAG is zero
2258; @note assumes it can trash eax and eflags
2259;
2260; @returns eax=0 on failure
2261; otherwise return address in eax
2262;
2263; @note NEVER change this without bumping the SSM version
2264align 32
2265BEGINPROC PATMRetFunction
2266PATMRetFunction_Start:
2267 push ecx
2268 push edx
2269 push edi
2270
2271 ; Event order:
2272 ; (@todo figure out which path is taken most often (1 or 2))
2273 ; 1) Check if the return patch address was pushed onto the PATM stack
2274 ; 2) Check if the return patch address can be found in the lookup table
2275 ; 3) Query return patch address from the hypervisor
2276
2277
2278 ; 1) Check if the return patch address was pushed on the PATM stack
2279 cmp dword [ss:PATM_STACKPTR], PATM_STACK_SIZE
2280 jae near PATMRetFunction_FindReturnAddress
2281
2282 mov edx, dword PATM_STACKPTR
2283
2284 ; check if the return address is what we expect it to be
2285 mov eax, dword PATM_STACKBASE_GUEST
2286 add eax, dword [ss:edx] ; stack base + stack position
2287 mov eax, dword [ss:eax] ; original return address
2288 cmp eax, dword [esp+12+16] ; pushed return address
2289
2290 ; the return address was changed -> let our trap handler try to find it
2291 ; (can happen when the guest messes with the stack (seen it) or when we didn't call this function ourselves)
2292 jne near PATMRetFunction_FindReturnAddress
2293
2294 ; found it, convert relative to absolute patch address and return the result to the caller
2295 mov eax, dword PATM_STACKBASE
2296 add eax, dword [ss:edx] ; stack base + stack position
2297 mov eax, dword [ss:eax] ; relative patm return address
2298 add eax, PATM_PATCHBASE
2299
2300%ifdef PATM_LOG_PATCHINSTR
2301 push eax
2302 push ebx
2303 push ecx
2304 push edx
2305 mov edx, eax ; return address
2306 lea ebx, [esp+16+12+16] ; stack address containing the return address
2307 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_RET
2308 mov eax, PATM_ACTION_LOG_RET
2309 mov ecx, PATM_ACTION_MAGIC
2310 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2311 pop edx
2312 pop ecx
2313 pop ebx
2314 pop eax
2315%endif
2316
2317 add dword [ss:edx], 4 ; pop return address from the PATM stack (sizeof(RTGCPTR); @note hardcoded assumption!)
2318
2319 pop edi
2320 pop edx
2321 pop ecx
2322 ret
2323
2324PATMRetFunction_FindReturnAddress:
2325 ; 2) Check if the return patch address can be found in the lookup table
2326 mov edx, dword [esp+12+16] ; pushed target address
2327
2328 xor eax, eax ; default result -> nothing found
2329 mov edi, dword [esp+12+4] ; jump table
2330 mov ecx, [ss:edi + PATCHJUMPTABLE.cAddresses]
2331 cmp ecx, 0
2332 je near PATMRetFunction_AskHypervisor
2333
2334PATMRetFunction_SearchStart:
2335 cmp [ss:edi + PATCHJUMPTABLE.Slot_pInstrGC + eax*8], edx ; edx = GC address to search for
2336 je near PATMRetFunction_SearchHit
2337 inc eax
2338 cmp eax, ecx
2339 jl near PATMRetFunction_SearchStart
2340
2341PATMRetFunction_AskHypervisor:
2342 ; 3) Query return patch address from the hypervisor
2343 ; @todo private ugly interface, since we have nothing generic at the moment
2344 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOOKUP_ADDRESS
2345 mov eax, PATM_ACTION_LOOKUP_ADDRESS
2346 mov ecx, PATM_ACTION_MAGIC
2347 mov edi, dword [esp+12+4] ; jump table address
2348 mov edx, dword [esp+12+16] ; original return address
2349 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2350 jmp near PATMRetFunction_SearchEnd
2351
2352PATMRetFunction_SearchHit:
2353 mov eax, [ss:edi + PATCHJUMPTABLE.Slot_pRelPatchGC + eax*8] ; found a match!
2354 ;@note can be zero, so the next check is required!!
2355
2356PATMRetFunction_SearchEnd:
2357 cmp eax, 0
2358 jz PATMRetFunction_Failure
2359
2360 add eax, PATM_PATCHBASE
2361
2362%ifdef PATM_LOG_PATCHINSTR
2363 push eax
2364 push ebx
2365 push ecx
2366 push edx
2367 mov edx, eax ; return address
2368 lea ebx, [esp+16+12+16] ; stack address containing the return address
2369 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_RET
2370 mov eax, PATM_ACTION_LOG_RET
2371 mov ecx, PATM_ACTION_MAGIC
2372 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2373 pop edx
2374 pop ecx
2375 pop ebx
2376 pop eax
2377%endif
2378
2379 pop edi
2380 pop edx
2381 pop ecx
2382 ret
2383
2384PATMRetFunction_Failure:
2385 ;signal error
2386 xor eax, eax
2387 pop edi
2388 pop edx
2389 pop ecx
2390 ret
2391
2392PATMRetFunction_End:
2393ENDPROC PATMRetFunction
2394
2395GLOBALNAME PATMRetFunctionRecord
2396 RTCCPTR_DEF PATMRetFunction_Start
2397 DD 0
2398 DD 0
2399 DD 0
2400 DD PATMRetFunction_End - PATMRetFunction_Start
2401%ifdef PATM_LOG_PATCHINSTR
2402 DD 9
2403%else
2404 DD 7
2405%endif
2406 DD PATM_STACKPTR
2407 DD 0
2408 DD PATM_STACKPTR
2409 DD 0
2410 DD PATM_STACKBASE_GUEST
2411 DD 0
2412 DD PATM_STACKBASE
2413 DD 0
2414 DD PATM_PATCHBASE
2415 DD 0
2416%ifdef PATM_LOG_PATCHINSTR
2417 DD PATM_PENDINGACTION
2418 DD 0
2419%endif
2420 DD PATM_PENDINGACTION
2421 DD 0
2422 DD PATM_PATCHBASE
2423 DD 0
2424%ifdef PATM_LOG_PATCHINSTR
2425 DD PATM_PENDINGACTION
2426 DD 0
2427%endif
2428 DD 0ffffffffh
2429
2430
2431;
2432; Jump to original instruction if IF=1
2433;
2434BEGINPROC PATMCheckIF
2435PATMCheckIF_Start:
2436 mov dword [ss:PATM_INTERRUPTFLAG], 0
2437 pushf
2438 test dword [ss:PATM_VMFLAGS], X86_EFL_IF
2439 jnz PATMCheckIF_Safe
2440 nop
2441
2442 ; IF=0 -> unsafe, so we must call the duplicated function (which we don't do here)
2443 popf
2444 mov dword [ss:PATM_INTERRUPTFLAG], 1
2445 jmp PATMCheckIF_End
2446
2447PATMCheckIF_Safe:
2448 ; invalidate the PATM stack as we'll jump back to guest code
2449 mov dword [ss:PATM_STACKPTR], PATM_STACK_SIZE
2450
2451%ifdef PATM_LOG_PATCHINSTR
2452 push eax
2453 push ecx
2454 lock or dword [ss:PATM_PENDINGACTION], PATM_ACTION_LOG_IF1
2455 mov eax, PATM_ACTION_LOG_IF1
2456 mov ecx, PATM_ACTION_MAGIC
2457 db 0fh, 0bh ; illegal instr (hardcoded assumption in PATMHandleIllegalInstrTrap)
2458 pop ecx
2459 pop eax
2460%endif
2461 popf
2462 mov dword [ss:PATM_INTERRUPTFLAG], 1
2463 ; IF=1 -> we can safely jump back to the original instruction
2464 DB 0xE9
2465PATMCheckIF_Jump:
2466 DD PATM_JUMPDELTA
2467PATMCheckIF_End:
2468ENDPROC PATMCheckIF
2469
2470; Patch record for call instructions
2471GLOBALNAME PATMCheckIFRecord
2472 RTCCPTR_DEF PATMCheckIF_Start
2473 DD PATMCheckIF_Jump - PATMCheckIF_Start
2474 DD 0
2475 DD 0
2476 DD PATMCheckIF_End - PATMCheckIF_Start
2477%ifdef PATM_LOG_PATCHINSTR
2478 DD 6
2479%else
2480 DD 5
2481%endif
2482 DD PATM_INTERRUPTFLAG
2483 DD 0
2484 DD PATM_VMFLAGS
2485 DD 0
2486 DD PATM_INTERRUPTFLAG
2487 DD 0
2488 DD PATM_STACKPTR
2489 DD 0
2490%ifdef PATM_LOG_PATCHINSTR
2491 DD PATM_PENDINGACTION
2492 DD 0
2493%endif
2494 DD PATM_INTERRUPTFLAG
2495 DD 0
2496 DD 0ffffffffh
2497
2498;
2499; Jump back to guest if IF=1, else fault
2500;
2501BEGINPROC PATMJumpToGuest_IF1
2502PATMJumpToGuest_IF1_Start:
2503 mov dword [ss:PATM_INTERRUPTFLAG], 0
2504 pushf
2505 test dword [ss:PATM_VMFLAGS], X86_EFL_IF
2506 jnz PATMJumpToGuest_IF1_Safe
2507 nop
2508
2509 ; IF=0 -> unsafe, so fault
2510 popf
2511 mov dword [ss:PATM_INTERRUPTFLAG], 1
2512 PATM_INT3
2513
2514PATMJumpToGuest_IF1_Safe:
2515 ; IF=1 -> we can safely jump back to the original instruction
2516 popf
2517 mov dword [ss:PATM_INTERRUPTFLAG], 1
2518 DB 0xE9
2519PATMJumpToGuest_IF1_Jump:
2520 DD PATM_JUMPDELTA
2521PATMJumpToGuest_IF1_End:
2522ENDPROC PATMJumpToGuest_IF1
2523
2524; Patch record for call instructions
2525GLOBALNAME PATMJumpToGuest_IF1Record
2526 RTCCPTR_DEF PATMJumpToGuest_IF1_Start
2527 DD PATMJumpToGuest_IF1_Jump - PATMJumpToGuest_IF1_Start
2528 DD 0
2529 DD 0
2530 DD PATMJumpToGuest_IF1_End - PATMJumpToGuest_IF1_Start
2531 DD 4
2532 DD PATM_INTERRUPTFLAG
2533 DD 0
2534 DD PATM_VMFLAGS
2535 DD 0
2536 DD PATM_INTERRUPTFLAG
2537 DD 0
2538 DD PATM_INTERRUPTFLAG
2539 DD 0
2540 DD 0ffffffffh
2541
2542
2543; check and correct RPL of pushed ss
2544BEGINPROC PATMMovFromSS
2545PATMMovFromSS_Start:
2546 push eax
2547 pushfd
2548 mov ax, ss
2549 and ax, 3
2550 cmp ax, 1
2551 jne near PATMMovFromSS_Continue
2552
2553 and dword [esp+8], ~3 ; clear RPL 1
2554PATMMovFromSS_Continue:
2555 popfd
2556 pop eax
2557PATMMovFromSS_Start_End:
2558ENDPROC PATMMovFromSS
2559
2560GLOBALNAME PATMMovFromSSRecord
2561 RTCCPTR_DEF PATMMovFromSS_Start
2562 DD 0
2563 DD 0
2564 DD 0
2565 DD PATMMovFromSS_Start_End - PATMMovFromSS_Start
2566 DD 0
2567 DD 0ffffffffh
2568
2569
2570
2571
2572; For assertion during init (to make absolutely sure the flags are in sync in vm.mac & vm.h)
2573GLOBALNAME PATMInterruptFlag
2574 DD VM_FF_INTERRUPT_APIC | VM_FF_INTERRUPT_PIC | VM_FF_TIMER | VM_FF_REQUEST
2575
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