Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Hi all. I found something interesting on this BrokenThorn page:
Entering v8086 Mode
These are the same steps involved when setting up v8086 mode. v8086 mode requires a user mode task in order to enter v86 mode. Thus, by doing the above, you can enter v86 mode as well. However, there is one slight modification needed.
Recall the format of the EFLAGS register. Bit 17 (VM) is the v8086 Mode Control Flag. Because we push a value for EFLAGS on the stack when performing an IRET, in order to enter v86 mode, just set bit 17 of EFLAGS before pushing it on the stack. This will cause IRET to set the VM bit in the EFLAGS register on return.
And this is what I found in Intel reference manual (Section 7.3.13.2 EFLAGS Transfer Instructions):
The PUSHF (push flags), PUSHFD (push flags double), POPF (pop flags), and POPFD (pop flags double) instructions
copy the flags in the EFLAGS register to and from the stack. The PUSHF instruction pushes the lower word of the
EFLAGS register onto the stack (see Figure 7-11). The PUSHFD instruction pushes the entire EFLAGS register onto
the stack (with the RF and VM flags read as clear).
I don't understand. Which from these is correct?:
The PUSHFD reads VM bit and POPFD reads it as zero
The PUSHFD operation doesn't read VM bit
Last edited by HugeCode on Sat Jun 29, 2013 2:09 am, edited 1 time in total.
In example 1, PUSHFD is never used, let alone mentioned. A value meant for EFLAGS is to be put on the stack.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
And now the code that doesn't belong to a different part of the tutorial, please. *facepalm*
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Combuster wrote:And now the code that doesn't belong to a different part of the tutorial, please. *facepalm*
That part of the tutorial is badly written, actually; there isn't any code to do the switch to V86 mode given (just the vague "since you're pushing EFLAGS, you can just set it there" bit).
To the OP: To do this, you'll have to replace PUSHFD in the example given with this (note: EAX gets trashed by this; if you want to preserve EAX, it'll take some juggling in place of the stack-fixing):
push eax
pushfd
pop eax ; gets the flags into somewhere useful
or eax, 00020000h ; sets VM bit
add esp, 4 ; fix stack so we overwrite the old value of EAX
push eax
The article summarizes the steps to enable virtual 8086 mode; we assumed the provided information from the article would be sufficient and that sample code would not be necessary. We discourage the use of pushf due to the transition between kernel mode and user mode; the process eflags is separate from the current kernel state (although to be fair, a better implementation of the routine should be in assembly only; only to execute the current user mode process or current thread.)
In any case, the software must push some value for the user mode eflags on to the current stack with eflags.VM (bit 17) set. Both MDenham's and Owen's method will work fine. Alternatively decide on some nice default eflags state (with bit 17 in that value set of course) and push that binary value rather then the eflags register itself.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Owen wrote:Oh come on... could you really have come up with a more convoluted way of modifying EFLAGS on the stack?
It was early, and the original intent was to write something that didn't trash EAX. I forgot to rewrite it afterwards to remove some of the extra code once I realized it wasn't going to avoid trashing EAX.
And now, for the correct way to do this without trashing any registers: