The i/o-sensitive instructions An introduction to the software emulation of i/o-sensitive instructions in Virtual-8086 mode Impact of IOPL in VM86 mode • In virtual-8086 mode, if IOPL<3, then any instructions which could alter the IF-bit in the FLAGS register (Interrupt Flag) cause a General Protection fault (Exception 0xD) • This lets the Virtual-8086 Monitor control the actual effect on the CPU Interrupt-Flag • The Monitor can ignore the instruction (by just skipping past it) or it can perform the operation on behalf of the VM86 program The six i/o-sensitive opcodes • • • • • • • CLI (Clear Interrupt flag) STI (Set Interrupt flag) PUSHF (Push Flags register to stack) POPF (Pop stack to Flags register) IRET (Return from Interrupt) INT-n (Software Interrupt) The 32-bit versions of these instructions are also i/o-sensitive (e.g., PUSHFD / POPFD / IRETD ) Role of the VM86 Monitor • The GP-fault handler may need to emulate the actions of the CPU when i/o-sensitive instructions trigger faults in VM86 mode • CLI and STI are simplest to emulate: all the Monitor needs to do is set or clear the IF-bit (bit #9) in the image of the EFLAGS register that the CPU saved on its ring-0 stack, and increment the image of IP by 1 Emulating ‘pushf’ • To emulate ‘pushf’ the cpu subtracts 2 from the SP-register’s image (to make room for a new word of its ring-3 stack), copies the saved FLAGS-register image from the ring-0 stack to this new word on its ring-3 stack, then add 1 to the IP image to skip past the ‘pushf’ opcode byte Emulating ‘popf’ • To emulate ‘popf’ the cpu copies the top word from its ring-3 stack to the lower half of the saved EFLAGS register-image on its ring-0 stack, adds 2 to the SP-register’s image (to discard the copied word), then adds 1 to the IP image (to skip past ‘popf’) Emulating ‘iret’ • To emulate ‘iret’ the cpu copies the three topmost words from its ring-3 stack onto the lower halves of the three doublewords on its ring-0 stack which hold the images of the EIP, CS, and EFLAGS registers, adds 6 to the saved SP-register image (to discard the three words just copied) Emulating ‘int-n’ • Emulating ‘int-n’ is the most complex of the i/o-sensitive instruction-emulations • We discussed the steps involved during our preceeding lecture (we conducted an in-class exercise that implemented them) • Our next slide briefly review those steps Steps for ‘int-n’ emulation • Add 2 to the IP register-image (to skip past int-n) • Decrement the SP register-image by 6 (to make room for 3 new words on the ring-3 stack), and the copy saved IF, CS, and FLAGS registerimages from the ring-0 stack to these new ring-3 stack locations • Use the interrupt ID-number (the second byte of ‘int-n’ instruction) to find the IVT entry, and copy its two words to the ring-0 stack locations for IP and CS, respectively • Clear bits #8 and #9 of the EFLAGS image Demo: ‘emulate.s’ • We have created a demo-program which incorporates these six emulations that we just discussed: CLI / STI, PUSHF / POPF, and IRET / INT-n. • But real-mode code for Pentium CPUs can also include 32-bit i/o-sensitive instructions (e.g., PUSHFD / POPFD, and IRETD) • These all have the operand-size prefix 0x66 in front of their one-byte opcodes In-class exercise #1 • Add emulations for these three additional i/o-sensitive instructions: • PUSHFD (0x66, 0x9C) • POPFD (0x66, 0x9D) • IRETD (0x66, 0xCF) • You will need to include some code in your VM86 procedure to ‘test’ your emulations In-class exercise #2 • Our emulation for ‘sti’ actually enables the receipt of device interrupts by the CPU • But we don’t provide interrupt-handlers! • This could easily cause a program crash • A ‘solution’ would be to ‘reflect’ any such interrupts to the real-mode ROM-BIOS interrupt-handlers (similar to emulating software interrupts) • So add this capability to your ‘emulate.s’