#53 Faked VxD support

closed
nobody
None
5
2014-03-15
2006-02-28
Simon White
No

Hi,

Am trying to run a dos piece of code that hooks into a
custom VxD. The DOS code is very old and binary only
but the hooks it uses are very simplistic.

The VxD runs various complicated libraries and drivers
under Windows, but there are equivalents available
under Linux. Am hoping to write a GPL dosemu plugin to
hooks onto these Linux equivalents.

I've worked out how to create a plugin that can do
various things. However I see what appears to be
hardcoded VxD handling for DPMI (perhaps something more
native for real Windows...?)

Was wondering if perhaps a new call could be added
"VxD_(Un)Register ( ) that takes an object. This
object could consist of the NAME to check (es:di string
check), and/or the ebx code and a function to call on
match.

Would such a thing be easily supportable?

Secondly I note that these entry points return function
pointers that are directly callable from DOS code.
Perhaps if possible some wrappers could be provided to
make it easy to convert such DOS calls to real C code
in Linux (or easy examples provided in vxd.h on how to
do such things).

Discussion

1 2 > >> (Page 1 of 2)
  • Simon White

    Simon White - 2006-02-28

    Logged In: YES
    user_id=59929

    The attached contains an updated vxd.c/h. They maynot
    compile but should be pretty close to correct. This
    provides a solution to the first part of the request.
    Presumably if there is support for native Windows (real)
    vxd's then that should occur after dosemu/plugin vxd handling.

     
  • Simon White

    Simon White - 2006-02-28

    Example vxd changes

     
  • Stas Sergeev

    Stas Sergeev - 2006-02-28

    Logged In: YES
    user_id=501371

    Would such a thing be easily supportable?
    I don't think it is very usefull. I doubt someone else
    will write such a plugins - the fact is, I am not aware
    about any 3d-party dosemu plugins, and you are the first
    one who decided to write a vxd for it. So it is obviously
    needed only for you. Also note that the entry points is
    the limited resource. Yes, we can reserve a few for the
    user's vxd plugins, but the amount of such a plugins
    will be limited.
    I wonder if your vxd is so specific that it can't be
    included into a main dosemu code? Currently the
    run-time plugins are used only to avoid the link-time
    dependancies on some libraries that may not be installed.

     
  • Stas Sergeev

    Stas Sergeev - 2006-02-28

    Logged In: YES
    user_id=501371

    Sorry, ignore that, I missed your second comment.
    Please update your code to the vxd.c from CVS and make
    a unidiff patch.

     
  • Simon White

    Simon White - 2006-02-28

    Logged In: YES
    user_id=59929

    I wonder if your vxd is so specific that it can't be
    included into a main dosemu code?

    That would be fine. I have time to spare to do this and
    don't mind doing it. Although maybe not usefull to others
    am really doing this to get my old games running better
    under Linux. I have a dos glide2x.ovl that hooks through
    via a vxd.

    I'll make a proper diff, but hoped you would see where I was
    going with those vxd.c/h changes and what you thought. Am
    not 100% familiar with the use of (e)bx in that int2f call
    only that glide2x.ovl sets it to 0 and provides the name via
    es:di like various other online examples.

    From what I can tell though my suggestion would allow any
    number of "faked" vxds to be added atleast on ebx=0. Now if
    I can only work out the thunk.

    I can see CISH(func) looks like is declares a compatible DOS
    function in assembly code. There some other bits about the
    special use of segment which indicates use of dpmi (if I
    understood correctly) that you then trap else where on a
    page fault.

    The DOS assembly code I cannot really see doing that much,
    haven't seen any that wrap to C code (perhaps it just causes
    the page fault). However the page fault handling does
    appear to hook into the C code so I assume thats thats how
    it is done.

    Am still not sure my understanding is fully correct here so
    advice welcomed.

    Anyway once I know how to get DOS to call my C function
    decoding of the information is passes is trivial and will
    allow me to call the appropriate glide (or openglide) functions.

     
  • Simon White

    Simon White - 2006-02-28

    Logged In: YES
    user_id=59929

    Diff attached against CVS.

     
  • Simon White

    Simon White - 2006-02-28
     
  • Simon White

    Simon White - 2006-02-28
     
  • Simon White

    Simon White - 2006-02-28

    Logged In: YES
    user_id=59929

    Some more searching and I've created a new better patch. If
    my understanding is correct then this allows two "generic"
    entry point calls to be externally registered from plugins
    and made callable from dos. The number of supported calls
    can be extended if this is the correct way to do this sort
    of thing.

    I'm guessing that once the page fault occurs then what was
    is the real cpu registers ends up in _AX, etc so function
    parameters from the DOS call can be accessed.

     
  • Stas Sergeev

    Stas Sergeev - 2006-03-01

    Logged In: YES
    user_id=501371

    Just a quick look:

    • There is some reserved space in bios.S after DPMI_VXD_end,
      please put your thunks here. The advantage is that the
      dpmi.c change won't be necessary.

    • if (!memcmp ((void *)SEGOFF2LINEAR(_ES, _DI), vxd->name,
      sizeof (vxd->name)))
      This doesn't look good to me, as according to RBIL,
      es:di is NULL.

    • +static struct vxd_client *vxds[0x10000] = {0};
      I wonder if this is necessary. Since we are going to
      have only a few vxds, maybe a thunks[] array alone
      will be enough, which you'll have to iterate completely,
      rather than to index by ID.

    Why does the glide need a pipe btw? Can't it be used
    as a library?

     
  • Simon White

    Simon White - 2006-03-01

    Logged In: YES
    user_id=59929

    • There is some reserved space in bios.S after DPMI_VXD_end,
      please put your thunks here. The advantage is that the
      dpmi.c change won't be necessary.

    Done.

    • if (!memcmp ((void *)SEGOFF2LINEAR(_ES, _DI), vxd->name,
      sizeof (vxd->name)))
      This doesn't look good to me, as according to RBIL,
      es:di is NULL.

    But does that matter? es:di is NULL but that is only 0 in
    DOS space, so assume has a real valid pointer in Linux. The
    test should never match. We can handle 0 if you still
    think it is important.

    • +static struct vxd_client *vxds[0x10000] = {0};
      I wonder if this is necessary. Since we are going to
      have only a few vxds, maybe a thunks[] array alone
      will be enough, which you'll have to iterate completely,
      rather than to index by ID.

    Done.

    -Why does the glide need a pipe btw? Can't it be used
    as a library?

    How do you mean? The DOS application uses real glide ovl
    that as far as I can tell directly goes to the hardware.
    For glide wrappers a custom ovl was created to loop through
    to a glide wrapper sitting on opengl or directx. I have
    that ovl but is old and is binary only. This I thought
    could be used to provide glide within the Linux environment.

    Please see the few remaining places I've marked FIXME.

     
  • Simon White

    Simon White - 2006-03-01
     
  • Stas Sergeev

    Stas Sergeev - 2006-03-01

    Logged In: YES
    user_id=501371

    But does that matter? es:di is NULL but that is only 0 in
    DOS space, so assume has a real valid pointer in Linux.
    Are you saying that after looking up the SEGOFF2LINEAR
    macro in cpu.h, or before?;)

    The test should never match.
    Then why doing it?

    Please see the few remaining places I've marked FIXME.
    I think your complain to the compiler is not valid,
    as these addresses are probably only known at link-time,
    not at a compile-time.

    What do you think about putting this all into
    src/dosext/dpmi, rather than into plugins? I am not
    against your registering technique, its fine, but
    why doing it a plugin? The main reason we use the
    plugins now is to relax the link-time dependancies.
    There are a few others, but we already have vxd.c, so
    I wonder whether having the vxds in more than one place
    is really needed.

     
  • Simon White

    Simon White - 2006-03-01

    Logged In: YES
    user_id=59929

    But does that matter? es:di is NULL but that is only 0 in
    DOS space, so assume has a real valid pointer in Linux.
    Are you saying that after looking up the SEGOFF2LINEAR
    macro in cpu.h, or before?;)

    I thought the es:di = 0 (or null in dos memory) would
    effectively be a real linux pointer of "dosmem_ptr + es:di"
    after the SEGOFF2LINEAR. Perhaps am wrong.

    The test should never match.
    Then why doing it?

    I meant specifically when es:di = 0. For other values we
    will get deliberate matches.

    Please see the few remaining places I've marked
    FIXME.
    I think your complain to the compiler is not valid,
    as these addresses are probably only known at link-time,
    not at a compile-time.

    Ahh good point although I thought the linker could only
    relocate data so although exact addresses may change the
    distance between two addresses in the same .o file would be
    the same.

    What do you think about putting this all into
    src/dosext/dpmi, rather than into plugins?

    I don't have a problem with this. If you specifiy names,
    locations then I'll adjust code to confirm. I was just
    following what I thought was the right thing.

    Btw the openglide code will end up with a dependency on
    libglide2x.so, is that an issue if built into the main code?
    To build dosemu the library would have to be present.

     
  • Stas Sergeev

    Stas Sergeev - 2006-03-02

    Logged In: YES
    user_id=501371

    I thought the es:di = 0 (or null in dos memory) would
    effectively be a real linux pointer of "dosmem_ptr +
    es:di" after the SEGOFF2LINEAR. Perhaps am wrong.
    Well, the code path is very small: you take SEGOFF2LINEAR,
    cast it to void* and pass to memcmp(). Where on these
    steps do you expect the offset is added?

    I meant specifically when es:di = 0. For other values we
    will get deliberate matches.
    But RBIL doesn't seem to even mention "the other values".
    I'd just remove that thing completely.

    distance between two addresses in the same .o file would
    be the same.
    Yes, but since they are located in a different link
    unit, the compiler doesn't know even the "distance".

    Btw the openglide code will end up with a dependency on
    libglide2x.so, is that an issue if built into the main
    code?
    Sure, but I thought since you use pipes, this is not
    a link-time dependancy, but the run-time one.
    Anyway, I think this is quite sufficient, lets do it
    your way then. :)

     
  • Simon White

    Simon White - 2006-03-02

    Logged In: YES
    user_id=59929

    Well, the code path is very small: you take SEGOFF2LINEAR,
    cast it to void* and pass to memcmp(). Where on these
    steps do you expect the offset is added?

    I've looked at the marco and ok, I'll convert to using the
    LINEAR2UNIX (is that the right one?). I based the code off
    here in lfn.c (line 646).

        dest = (char *)SEGOFF2LINEAR(_ES, _DI);
        memset(dest, 0, 0x20);
    

    Is that code correct then, is the above a real address you
    can call memset on?

    But RBIL doesn't seem to even mention "the other
    values".
    I'd just remove that thing completely.

    I see here something like you state (only references to
    es:di being 0) and that vxd ids must be registered with
    Microsoft:

    http://oopweb.com/Assembly/Documents/InterList/Volume/INTERRUP.L

    However http://www.faqs.org/faqs/windows/programming/vxd/
    clearly states es:di can be non 0 and that is a Windows
    supported feature.

    Do I need a Device ID for my VxD?

    Most developers will not need a device ID. To communicate
    with a VxD from a Win32 application, use the Device IOCTL
    call. To obtain the VxD entry point from a 16-bit
    application running under Windows 95 given the device
    name (1-8 characters) without needing an ID number, do this:

           AX =3D 1684h (Get VxD entry point)
           BX =3D 0000h (UNDEFINED_DEVICE_ID)
           ES:DI -> 8-character space-padded case-sensitive
    
                    buffer with the VxD name.
           Int 2Fh
    

    This will return ES:DI =3D callback address if successful,
    or 0 on= error. For example, if your device is called
    "MYDEV", you could write

     MyDevName db 'MYDEV   ' ; 8 characters space-padded
                             ;  case-sensitive
          mov ax, 1684h
          mov bx, 0
          push ds
          pop es
          mov di, offset MyDevName
          int 2fh
          mov ax, es
          or ax, di
          jz error
          mov word ptr EntryPoint[0], di
          mov word ptr EntryPoint[2], es
    

    If your driver provides services to be called by other VxDs,
    you may want a unique device ID. Send email to
    vxdid@microsoft.com and an application for a device ID will
    be automatically sent to you.

    Also in the first article there any many VxDs using bx = 0
    so there must be some way to distinguish between them.

     
  • Bart Oldeman

    Bart Oldeman - 2006-03-02

    Logged In: YES
    user_id=176505

    LINEAR2UNIX(addr) converts a linear DOS point-of-view
    address to something that make sense in Linux. It's either
    the same (void*)(addr) or resolves to lowmem_base+addr. In
    fact normal DOS RAM under 1M+64K is mapped twice, once at 0
    and once at lowmem_addr. DOSEMU tries to access it at
    lowmem_addr because that avoids page faults: the memory at 0
    may be write protected for the cpu emulator.

    Now: SEGOFF2LINEAR applies to real mode addresses, which
    is why Stas asked you to look it up.

    However, you are not hooking int2f/ax=1684 as a real mode
    (vm86 really, but we know that) interrupt. Would it be a
    real mode interrupt then it would be hooked via
    src/base/async/int.c:int2f()
    vxd.c hooks it as a protected mode interrupt using a GPF
    (not page fault); the sequence is:
    src/arch/linux/async/sigsegv.c:dosemu_fault1()
    calls dosemu_fault1, which calls dpmi_fault.
    Then dpmi_fault sees a 0xcd 0x2f opcode at cs:eip, calls
    do_dpmi_int, and that calls get_vxd_entry().

    In protected mode you have to use SEL_ADR(_es,_di) function
    to get what es:di points to (note _es, not _ES: _es =
    scp->es applies in pm, and _ES applies for vm86).
    Then you can cast the result of SEL_ADR to (char *), or
    (better, but doesn't matter for read/only access) use
    LINEAR2UNIX.

    Hopefully that helps a bit understanding some dosemu internals.

     
  • Stas Sergeev

    Stas Sergeev - 2006-03-02

    Logged In: YES
    user_id=501371

    I've looked at the marco and ok, I'll convert to using
    the LINEAR2UNIX (is that the right one?).
    No, but that was already explained by Bart.

    Is that code correct then, is the above a real address you
    can call memset on?
    That code is correct, but according to our convention,
    it had to use MEMSET_DOS instead of the plain memset().
    But it is still correct. (again, already explained)

     
  • Stas Sergeev

    Stas Sergeev - 2006-03-02

    Logged In: YES
    user_id=501371

    (better, but doesn't matter for read/only access)
    That does matter though. If it didn't, there wouldn't be
    a hope for the null-page protection, which denies both
    the read and write. (SEL_ADR can return the low/SHM
    addresses too)

    use LINEAR2UNIX.
    AFAIK the convention is to use the READ_XXX/YYY_2DOS etc
    where possible, rather than the plain LINEAR2UNIX, but
    that shouldn't matter much.

     
  • Simon White

    Simon White - 2006-03-03

    Logged In: YES
    user_id=59929

    I'm trying to perform some testing. I've performed a cvs
    update -d -P as of 3:05 GMT from the public repository and
    the code segfaults.

    I've removed all my changes and it dosen't, fair enough.
    Add in just the change to vxd.h and a basic openglide.c
    causes it to segfault (no other changes). Commenting out
    the struct vxd_client pipe[2]; prevents segfaulting.

    This seems a bit wierd in that the object isn't even used.
    Only thing I can think of is that other things have been
    moved in memory and upset something. Am using gcc 4.0.1
    from Mandriva Linux 2006.

    vxd.h added-----------------------------------------
    struct vxd_client
    {
    char name[8];
    unsigned short dev_id;
    void (entry)(struct sigcontext scp);
    unsigned short thunk;
    struct vxd_client *next;
    };

    void register_vxd_client (struct vxd_client *vxd);

    openglide.c------------------------------------------

    include <stdio.h>

    include <string.h>

    include "config.h"

    include "cpu.h"

    include "../../../src/dosext/dpmi/vxd.h"

    / These vxd's are used to provide a pipe type interface
    * that the dos glide2x.ovl expects
    /
    struct vxd_client pipe[2];

    void openglide_plugin_init(void)
    {
    //#if 0
    fprintf(stderr, "PLUGIN: openglide_plugin_init called\n");
    //#endif
    }

    void openglide_plugin_close(void)
    {
    //#if 0
    fprintf(stderr, "PLUGIN: openglide_plugin_close called\n");
    //#endif
    }

    The backtrace is:

    (gdb) bt

    0 0x0862808d in ?? ()

    1 0xbfea40b4 in ?? ()

    2 0xbfea40a4 in ?? ()

    3 0x00000001 in ?? ()

    4 0x0000000d in ?? ()

    5 0x0862adb8 in ?? ()

    6 0x0862adb7 in ?? ()

    7 0x00000006 in ?? ()

    8 0x0aea40b8 in ?? ()

    9 0xb7eb76ef in malloc () from /lib/tls/libc.so.6

    10 0x08112098 in yyparse () at parser.y:402

    11 0x0811a3d9 in do_parse (fp=0x0, confname=0x81a071b

    "built-in global.conf", errtx=0x81a06fd "error in built-in
    global.conf") at parser.y:2729

    12 0x0811a5be in parse_config (confname=0x0, dosrcname=0x0)

    at parser.y:2778

    13 0x08124e94 in config_init (argc=1, argv=0xbfeb4da4) at

    config.c:954

    14 0x0805e3d7 in main (argc=1, argv=0xbfeb4da4) at emu.c:345

     
  • Simon White

    Simon White - 2006-03-03

    Logged In: YES
    user_id=59929

    Oops partial lie. Is only sometimes working with that line
    commented out. Sometimes does fall over but not with
    segfault. Am getting:

    PLUGIN: openglide_plugin_init called
    ERROR: cpu exception in dosemu code outside of VM86()!
    trapno: 0x0e errorcode: 0x00000004 cr2: 0x00c38790
    eip: 0x00c38790 esp: 0xbf82346c eflags: 0x00210296
    cs: 0x0073 ds: 0x007b es: 0x007b ss: 0x007b
    PLUGIN: openglide_plugin_close called

    or

    PLUGIN: openglide_plugin_init called
    ERROR: cpu exception in dosemu code outside of VM86()!
    trapno: 0x0e errorcode: 0x00000004 cr2: 0x00c38790
    eip: 0x00c38790 esp: 0xbfa5ca7c eflags: 0x00210296
    cs: 0x0073 ds: 0x007b es: 0x007b ss: 0x007b
    PLUGIN: openglide_plugin_close called
    ERROR: Fatal X error, leaving
    ERROR: leavedos called recursively, forgetting the graceful
    exit!

     
  • Stas Sergeev

    Stas Sergeev - 2006-03-03

    Logged In: YES
    user_id=501371

    Actually I already have that problem reported (privately),
    now your confirmed its existance, even though I can't
    reproduce it.
    Could you please open a bug entry for it and do the CVS
    search, like
    cvs update -D "1 week ago"
    cvs update -D "1 month 1 week ago"
    etc and find the problematic patch that way?

     
  • Simon White

    Simon White - 2006-03-04

    Logged In: YES
    user_id=59929

    The segfault problem I traced and found it to be due to the
    pipe call in run_shell in parser.y. Theres a symbol clash
    between my pipe variable and the pipe function call there.
    This is a big problem I've generally found with C, peoples
    code un-related accidently calling yours in big projects
    including lots of libraries.

    I rarely see this problem due to mostly using C++, hence
    name mangling and namespaces.

    This still leaves that cpu exception in dosemu code outside
    of VM86, investigating, however bare with me I am not at all
    familiar with Subversion (now that you've switched).

     
  • Simon White

    Simon White - 2006-03-04

    Logged In: YES
    user_id=59929

    Hope this helps:

    emu.c

    printf ("here\n");
    fflush (stdout);
    // timer_interrupt_init(); / start sending int 8h int
    signals
    /

    printf ("here2\n");
    fflush (stdout);

    /* remap conventional memory just before booting */
    mmap_mapping(MAPPING_LOWMEM, 0, config.mem_size * 1024,
                 PROT_READ | PROT_WRITE | PROT_EXEC, (void *)0);
    

    printf ("here3\n");
    fflush (stdout);

    while (!fatalerr && !config.exitearly) {
        loopstep_run_vm86();
    }
    

    printf ("here4\n");
    fflush (stdout);

    here4 dosen't print out. From testing it looks like a
    SIGALRM has triggered during loopstep_run_vm86. sigalrm
    does run and it does return but never manages to get back to
    running dosemu code.

     
  • Bart Oldeman

    Bart Oldeman - 2006-03-04

    Logged In: YES
    user_id=176505

    With svn it may be easier to search using revision numbers.
    E.g. dosemu 1.3.3 corresponds to rev 1429, and the current
    trunk HEAD is at 1563.

    svn up -r1429
    brings you to 1.3.3

    svn up -r1500
    somewhere in between

    svn up
    back to current. Dates also work like this:
    svn up -r "{"2006-02-25"}"
    Hope that helps.

     
1 2 > >> (Page 1 of 2)

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks