VirtualBox

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

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

The Big Sun Rebranding Header Change

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