VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PATMA.asm@ 54686

最後變更 在這個檔案從54686是 54686,由 vboxsync 提交於 10 年 前

PATM: Added some comments and formalized the reloc array type (instead of having two anonymous uint32_t's).

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette