* How to Use the vm86 System Call
@ 2005-09-15 18:04 Richard Cooper
2005-09-15 19:52 ` Claudio Fontana
0 siblings, 1 reply; 5+ messages in thread
From: Richard Cooper @ 2005-09-15 18:04 UTC (permalink / raw)
To: linux-assembly
Does anyone know how to make use of the vm86 system call? The man page for it is pretty light on the details, and the names of the fields of the structures in the header file aren't very explanatory.
All I can seem to find on the internet is stuff like this:
16:02:17 <SLACKo> anyone knows how to use vm86() ?
16:02:24 <SLACKo> system call
16:02:59 <SLACKo> how can I creat the struct vm86plus_struct
16:03:03 <SLACKo> ?
16:03:15 <SLACKo> I couldn't find any documentation on that
16:06:53 <air> #include <sys/vm86.h>
16:07:13 <air> /usr/include/sys/vm86.h
16:07:22 <air> all the documentation u could ever want
16:07:48 <SLACKo> couldn't find what the struct members should contain
16:07:55 <SLACKo> :(
16:08:23 <SLACKo> struct vm86plus_struct {
16:08:24 <SLACKo> struct vm86_regs regs;
16:08:24 <SLACKo> unsigned long flags;
16:08:24 <SLACKo> unsigned long screen_bitmap;
16:08:24 <SLACKo> unsigned long cpu_type;
16:08:26 <SLACKo> struct revectored_struct int_revectored;
16:08:26 <SLACKo> struct revectored_struct int21_revectored;
16:08:28 <SLACKo> struct vm86plus_info_struct vm86plus;
16:08:36 <SLACKo> };
It seems so hopeless.
I was working on a new Softer-like thing, except that it would work in framebuffer mode too, and it would just provide video access rather than all of that "orange protocol" stuff. However, I'm writing it to use with a game that I want to release as shareware, but if the game is shareware, then I want it to work well for people (so that they'll give me money), and part of working well is being able to run it in whatever video mode the user wants. With framebuffer, you only get the one video mode that the framebuffer is in, and that's not very nice since the user might want framebuffer in 1600x1200 because they run X in framebuffer mode, but in all likelyhood they'd rather run the game in something like 640x480. I'd much rather just call the VESA BIOS and be able to make it support every mode available in both text mode and framebuffer mode rather than deal with the unstability of SVGA
lib or the "maybe we can change modes, and maybe we can't" stuff you get with things like SDL
under X, but the vm86 call doesn't seem to be documented anywhere.
I actually decided to write the thing in Windows because of that, but reading through the Windows documentation, I'm not sure how much of that hungarian notation I can tolerate. If I could just figure out how to use this vm86 call then I could make the game support the video modes that I want it to support, and then I wouldn't have to learn to program for a whole new OS, and I could write the game in Linux like I origionally wanted to.
(And just in case anyone is wondering, the part that does the graphics modes would be public domain just like Softer, only the game itself would be closed source shareware.)
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: How to Use the vm86 System Call 2005-09-15 18:04 How to Use the vm86 System Call Richard Cooper @ 2005-09-15 19:52 ` Claudio Fontana 2005-09-15 20:48 ` Richard Cooper 0 siblings, 1 reply; 5+ messages in thread From: Claudio Fontana @ 2005-09-15 19:52 UTC (permalink / raw) To: Richard Cooper; +Cc: linux-assembly Hello, --- Richard Cooper <peajay@funrestraints.com> wrote: > > Does anyone know how to make use of the vm86 system > call? I don't, but maybe I can provide some info. > The man page for it is pretty light on the > details, and the names of the fields of the > structures in the header file aren't very > explanatory. I hope this info can be of some use: sh-3.00$ gdb dosemu.bin (gdb) ptype struct vm86plus_struct type = struct vm86plus_struct { struct vm86_regs regs; long unsigned int flags; long unsigned int screen_bitmap; long unsigned int cpu_type; struct revectored_struct int_revectored; struct revectored_struct int21_revectored; struct vm86plus_info_struct vm86plus; } (gdb) ptype struct vm86_regs type = struct vm86_regs { long int ebx; long int ecx; long int edx; long int esi; long int edi; long int ebp; long int eax; long int __null_ds; long int __null_es; long int __null_fs; long int __null_gs; long int orig_eax; long int eip; short unsigned int cs; short unsigned int __csh; long int eflags; long int esp; short unsigned int ss; short unsigned int __ssh; short unsigned int es; short unsigned int __esh; short unsigned int ds; short unsigned int __dsh; short unsigned int fs; short unsigned int __fsh; short unsigned int gs; short unsigned int __gsh; } (gdb) ptype struct revectored_struct type = struct revectored_struct { long unsigned int __map[8]; } (gdb) ptype struct vm86plus_info_struct type = struct vm86plus_info_struct { long unsigned int force_return_for_pic : 1; long unsigned int vm86dbg_active : 1; long unsigned int vm86dbg_TFpendig : 1; long unsigned int unused : 28; long unsigned int is_vm86pus : 1; unsigned char vm86dbg_intxxtab[32]; } (gdb) You can study the dosemu source code for examples of use. However, I would rather use SDL instead. Bye, Claudio __________________________________ Yahoo! Mail - PC Magazine Editors' Choice 2005 http://mail.yahoo.com ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: How to Use the vm86 System Call 2005-09-15 19:52 ` Claudio Fontana @ 2005-09-15 20:48 ` Richard Cooper 2005-09-15 22:07 ` Richard Cooper 0 siblings, 1 reply; 5+ messages in thread From: Richard Cooper @ 2005-09-15 20:48 UTC (permalink / raw) To: Claudio Fontana; +Cc: linux-assembly On Thu, 15 Sep 2005 15:52:04 -0400, Claudio Fontana <sick_soul@yahoo.it> wrote: > (gdb) ptype struct vm86plus_info_struct > type = struct vm86plus_info_struct { > long unsigned int force_return_for_pic : 1; > long unsigned int vm86dbg_active : 1; > long unsigned int vm86dbg_TFpendig : 1; > long unsigned int unused : 28; > long unsigned int is_vm86pus : 1; > unsigned char vm86dbg_intxxtab[32]; > } Yes, that's about where I'm at. The questions I have are along the lines of "what does is_vm86pus do?" and "how do I put all of this together into a working program?" I don't think reading any source code is going to do me any good. Typically, comments only cover what the program is doing, not the details of the system calls. When was the last time you read a comment like "open() will open the file, the first operand is a pointer to a null terminated string, which is the file we want to open..." Granted, I could figure out things like the file name, but the source is just going to set is_vm86pus to 1 or 0 and probably never mention what it does, forcing me to wonder if maybe I should be setting it the other way for what I'm doing. On the other hand, what else have I got to do? (besides learn windows) Assuming I can still get Linux to boot (lilo did a fun number on my windows drive and I haven't yet seen if the Linux one still works or not), I'll have a look and see if I can figure anything out. I know that dosemu, svgalib, and X all use vm86, so maybe between the three of them I can at least figure out half of it. > However, I would rather use SDL instead. That would be the easy thing to do, but SDL just uses X or SVGAlib depending on where it's run under X or on a console, and so it won't get me anything that those two won't. SVGAlib is just too unstable for me to want to use it, and only some of the X drivers support mode switching, the others require to you restart the X server to change modes, and if you're using the X framebuffer driver, you have to reboot Linux as well. It used to be that you never had to reboot Linux for anything short of installing a new kernel, but the state of graphics support is changing that. With this vm86 call I'm hoping to get things to where they should be, you decide you want a different mode and two seconds later you've got it, no restarts or reboots required. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: How to Use the vm86 System Call 2005-09-15 20:48 ` Richard Cooper @ 2005-09-15 22:07 ` Richard Cooper 2005-09-16 6:28 ` Richard Cooper 0 siblings, 1 reply; 5+ messages in thread From: Richard Cooper @ 2005-09-15 22:07 UTC (permalink / raw) To: linux-assembly On Thu, 15 Sep 2005 16:48:18 -0400, Richard Cooper <peajay@funrestraints.com> wrote: > I'll have a look [at various source codes]and see if I can figure > anything out. Damn, I wish I would have just done that right from the beginning... Turns out SVGAlib does all of the vm86 stuff through a file called lrmi.c. So I looked in lrmi.c and at the top is this comment about how it's the "Linux Real Mode Interface" and some other stuff that makes it sound an awful lot like public domain. So I went and found the "Linux Real Mode Interface" and downloaded it. It's just a few C files along with a makefile to make a little test program. It looks pretty nice, at least the test program compiled without warnings and didn't require me to install any libraries, and as an added surprise, worked without a problem. (looks like all the test program does is let you pick a VESA mode, then it sets it for five seconds, then restores the old mode, but that's enough to say that it works) Since it's mostly compatible with public domain, I don't even have to try to figure out how it works, I can just use it. I'm not sure if the test program does VBE 1.2 or not, but I'm sure I can figure that out on my own. I'd still like to know how that vm86 call works, but this should work just fine for what I'm doing. It's so nice to be in Linux again... Copy and paste doesn't work in Windows. (At least not with the middle mouse button, which is how I usually do it.) Interestingly, I've learned that there're 357 people signed up to this mailing list. I had no idea. I thought it was more like 20 or 30. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: How to Use the vm86 System Call 2005-09-15 22:07 ` Richard Cooper @ 2005-09-16 6:28 ` Richard Cooper 0 siblings, 0 replies; 5+ messages in thread From: Richard Cooper @ 2005-09-16 6:28 UTC (permalink / raw) To: Richard Cooper; +Cc: linux-assembly I've looked over the source for LRMI, and here's what I've discovered about the vm86 call, just in case someone cares. Feel free to turn this into a webpage or something if you feel the urge. I should add that LRMI (Linux Real Mode Interface) is the finest piece of code I've ever seen. I'm used to not liking other people's code at all, but I like this code better than code that I write myself. It's easy to read, there are very few comments but the variable and function names are nearly always descriptive, and it looks as if the author considered every possible thing that might happen and made the code handle it appropriately. So if it provides everything that you need, I'd recommend that you just use the LRMI code instead of writing your own. Unless you're some kind of genius, I don't think your code will be any better. This code is just awesome. Overview: ========= When you call vm86 (the number 113 vm86, at least), the real-mode process inherits your processes address space. So before calling vm86, you need to map everything you want in the real-mode address space into your address space, at the offsets where you want it to be at. You also need to allocate any RAM that you want to exist in real mode. Zero the entire vm86_struct, as it seems that fields not mentioned here should be set to zero. Then you set the int_revectored field of vm86_struct to specify which interrupts you want to receive from real-mode, and which ones you want Linux to handle automatically for you. (I assume it just calls the real-mode interrupt handler.) Then you load the vm86_regs structure in vm_86_struct with what you want the initial register contents of the real mode process to be. Depending on what you are doing, you will probably want to set up a stack at least. The real-mode process inherits your FS and GS selectors, the fs and gs fields in vm86_regs are (I guess) only for return values. You can either leave them as they are, giving the real-mode process access to your protected mode address space via FS and GS, or you can load them with real-mode selectors before calling vm86. Then you call vm86. vm86 runs until either a real-mode interrupt occurs, a not-allowed-in-vm86-mode opcode is executed, or some other miscellaneous error occurs. A handy way to allow your real-mode code to exit the vm86 call is to have it call interrupt 255, which you previously set to be one which you wish to receive. Upon return from vm86, the vm86_regs structure contains all of the register contents from the real-mode process. The return value of vm86 contains two fields, a type field and an argument field, the type field being the lowest 8 bits, and the argument field being the eight bits above that. If the type field is VM86_INTx, then the argument field is the number of the interrupt that was called. Various Details: ================ There are two vm86 system calls. LRMI makes sure to get the one that is numbered 113. This is the one declared as such: int vm86(struct vm86_struct *); The other one takes an additional parameter, about which I know nothing. Here is vm86_struct: struct vm86_struct { struct vm86_regs regs; unsigned long flags; unsigned long screen_bitmap; unsigned long cpu_type; struct revectored_struct int_revectored; struct revectored_struct int21_revectored; }; LRMI begins by simply setting the entire thing to zero. flags, screen_bitmap, cpu_type, and int21_revectored are never accessed by LRMI, except when it zeros the entire structure, so I don't know what any of them do. int_revectored appears to be a bitmask, with one bit for each interrupt. Setting a bit to 0 tells Linux that you want it to emulate that interrupt. Setting a bit to 1 tells Linux that you want to service that interrupt. I'm not sure if this is reliable, as there's also code in LRMI that emulates the interrupt if Linux doesn't, but maybe that's just a failsafe. vm86_regs looks like this: struct vm86_regs { /* * normal regs, with special meaning for the segment descriptors.. */ long ebx; long ecx; long edx; long esi; long edi; long ebp; long eax; long __null_ds; long __null_es; long __null_fs; long __null_gs; long orig_eax; long eip; unsigned short cs, __csh; long eflags; long esp; unsigned short ss, __ssh; /* * these are specific to v86 mode: */ unsigned short es, __esh; unsigned short ds, __dsh; unsigned short fs, __fsh; unsigned short gs, __gsh; }; All of the register fields are what you would expect. LRMI never accesses orig_eax, or any of the __null_ segment registers. Linux ignores the fs and gs fields. (I think that's worth mentioning twice.) LRMI loads it's own FS and GS with the real-mode process' FS and GS before calling vm86, and restores it's old FS and GS after the call returns. It does not save the contents of FS and GS upon return from vm86, leading me to believe that Linux saves them in vm86_regs. LRMI maps address 0x00000 size 0x400 into it's memory space, so that it has the origional interrupt table from when the computer booted. It also maps address 0x00400 size 0x00102, as this is the BIOS data area. It also maps address 0xA0000 size 0x60000, to map in any ROMs that may be in that area. LRMI maps an anonymous block of /dev/zero of size 0x40000 to address 0x10000. It uses this memory in it's own internal LRMI_alloc_real function which allocates memory in the real-mode address space. Although the real-mode process inherits your address space, it does not appear to inherit your I/O permissions. Either that or the code to emulate I/O instructions in LRMI is never being used. These are the possible type codes for the vm86 return value: #define VM86_SIGNAL 0 /* return due to signal */ #define VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */ #define VM86_INTx 2 /* int3/int x instruction (ARG = x) */ #define VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */ If the return code is VM86_UNKNOWN, then LRMI checks to see if it's an opcode that it knows how to emulate. It emulates every opcode that operates on an I/O port, and thus I assume that those opcodes must be emulated. Additionally, it emulates segment overrides, data size overrides, and repeat prefixes, taking into account the direction flag. It ignores the address size override, as well as the F0 and F2 prefixes. If the instruction isn't one which it knows how to emulate, it appears to have a nice piece of code that prints a register dump of the real mode registers. It also calls this function if the return value type is anything other than VM86_INTx or VM86_UNKNOWN. I believe that it's possible that nothing has to be done for VM86_STI. Judging from the comment in the structure above, it sounds like it's mearly a signal to let you know that interrupts were enabled. Additionally, I believe VM86_SIGNAL is just like the EINTR return value of many other functions, that is, it simply indicates that your process recieved a signal, but that the vm86 process is otherwise just fine. This might be useful if you wish to only allow the vm86 process to run for a limited time. You could use the alarm or itimer system calls to schedual an alarm signal, and when that signal occurs, the vm86 call will exit. That's it, hopefully I didn't forget anything. ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2005-09-16 6:28 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2005-09-15 18:04 How to Use the vm86 System Call Richard Cooper 2005-09-15 19:52 ` Claudio Fontana 2005-09-15 20:48 ` Richard Cooper 2005-09-15 22:07 ` Richard Cooper 2005-09-16 6:28 ` Richard Cooper
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox