[haiku-development] Re: Virtual 8086 mode support

  • From: Ingo Weinhold <ingo_weinhold@xxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Sun, 20 Apr 2008 14:14:36 +0200

On 2008-04-20 at 11:17:48 [+0200], Jan Klötzke <jan.kloetzke@xxxxxxxxxx> 
wrote:
> Am Samstag, 19. April 2008 schrieb Axel Dörfler:
> > > Nice! I wonder, why this is a syscall, though. If the intended use is
> > > for the
> > > VESA driver, it won't really help. Or do I miss something?
> 
> Even though it may sound strange it was (for the first step) the easiest way
> to implement it.
> 
> > The VESA driver also has an accelerant. I dunno if one need this
> > functionality in userland, but you'd need a syscall anyway to offload
> > that functionality to the driver (just an ioctl(), of course).
> > Since you want to access low memory (and would need a dedicated kernel
> > thread to do so in the kernel, otherwise it's mapped by some app), it
> > might even only be possible to do that in userland ATM.
> 
> That's pretty much the explanation for why I did it as syscall. First of 
> all I
> see no way on how to do it from a kernel thread. The kernel teams address
> space starts from 0x80000000 but in vm86 mode the thread will run in the 1st
> Mb of the address space. So it must be done in the context of a user mode
> thread unless I overlooked something.

It might be a bit more involved, but of course you could map the address 
space you need in a kernel thread. In the kernel team the address space 
reserved for userland teams is simply unused. I don't think a separate kernel 
thread is needed, though.

> I also thought about to provide a kernel vm86() function but did not do it 
> in
> the first step. I did not came up with a clean solution yet.
> 
> Currently I manipulate the iframe from the vm86() syscall to go to vm86 mode
> when the syscall trap handler is left. As soon as a signal is delivered or a
> #GP exception happens I restore the vm86() syscall iframe and the 
> application
> will "return" from the vm86() syscall.
> 
> Using vm86 mode directly from the kernel space is a little bit more
> complicated. Basically the driver needs also a vm86() function to
> say "execute this piece in vm86 mode". But in the end the kernel vm86()
> function has to do a "iret" because it's the only way on the x86 to switch 
> to
> vm86 mode. But this leaves the ioctl() syscall iframe on the ring 0 stack ->
> therefore we would have to switch to an alternate ring 0 stack or the task
> would overwrite the old ioctl() iframe when it returns from vm86 mode. Not
> very nice...

That should be the smallest problem actually. Just set up the stack and do an 
iret.

> On the other hand the current user mode solution also has a drawback. When 
> the
> BIOS tries to execute a IN/OUT instruction the CPU will assert a #GP
> exception (because it's a privileged insn) and the user mode part has to
> examine what happened (IN/OUT executed). Then the user mode task will have 
> to
> do the IN/OUT itself and resume execution of the BIOS. But the user mode
> thread is also not allowed to do it. So eighther the kernel mode driver
> provides a ioctl() to do IN/OUT's or we provide a new facility to give a
> thread the rights to execute IN/OUT instructions itself, that is to raise
> it's IOPL to 3.

That's why I was wondering about the usefulness of the syscall. You can't do 
the interesting stuff, unless you allow the vm86 code to execute privileged 
instructions -- in which case any userland app could do that.

I would simply reserve a small piece of the required address space and do the 
vm86 stuff fully in the kernel (i.e. available to userland via an ioctl() 
only). When the driver needs to execute vm86 code, an area with the code to 
execute and the stack are mapped into the reserved region (cloned or copied 
-- whatever makes sense), the code is executed, and when done the area is 
unmapped again. That's not high-performance, but for stuff like resolution 
changes, it should be totally sufficient.

CU, Ingo

Other related posts: