[<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]

   CPMI Overview
   =======================================================================

   The CA-Clipper community has been blessed in recent months with the
   ability to create Clipper applications that run in protected mode.
   There are currently three different products (and who knows, maybe more
   to come) that alleviate many memory problems associated with Clipper
   programming and have brought relief to long-suffering developers.

   As with all silver linings, however, this one has a dark cloud <g>.
   Many third-party libraries, as well as some home-grown C / ASM code,
   will not work with these products because they break protected mode
   programming rules (no one's fault, really -- the DOS extender products
   are very new and prior to their release no one expected Clipper apps to
   ever run in anything but real mode).  To their credit, the vendors of
   the DOS extender products have attempted to minimize the problem by
   providing APIs that can be used to make C or assembler code compatible
   with protected mode.  Unfortunately, each vendor uses its own set of
   API functions, so a function written for one API will not work when
   used with a different DOS extender.

   The Clipper Protected Mode Interface (hereafter called CPMI) is an
   attempt to solve this problem.  It provides a set of generic functions
   that will work regardless of which DOS extender is used.  This is made
   possible by the fact that all the existing extender products support
   the use of the DOS Protected Mode Interface (DPMI) specification, even
   when the application is not running under a DPMI host.  The functions
   in the CPMI API use DPMI calls to achieve compatibility with any DOS
   extender that supports the DPMI protocol.

   Another attractive feature is that the CPMI is Public Domain, so it may
   be freely distributed by third-party developers and anyone else who
   needs its services.  It is hoped that this will simplify compliance
   with protected mode rules since it is no longer necessary to support
   each vendor's API.



   Programming in protected mode
   ========================================================================

   Although coding for protected mode is a new experience for most of us,
   it is not difficult and any code will run fine as long as a few simple
   rules are followed.  Failure to follow the rules will result in a
   General Protection Fault (GPF), which is actually nice in a way because
   it makes finding memory-related bugs much easier.  Adhere to the
   following rules and you should be able to avoid GPFs:

   1.  A selector value (referred to as a segment value in real mode)
       loaded into a segment register actually maps to a chunk of memory
       that may be located anywhere within the physical address space.
       With extenders that support virtual memory, the selector can even
       refer to memory that has been swapped to disk.

       a)  Never load a segment register with junk values or a GPF will
           probably occur.  Every time a segment register is loaded with a
           value the microprocessor checks to make sure it is a valid
           selector and generates a GP fault if it is not.

       b)  Never perform segment arithmetic on a selector value.  This is
           done in real mode code to either normalize a pointer, force
           segments to be aligned on a specific boundary, or to access
           data that is greater than 64K in size.  A selector value is a
           unique ID which has no relationship to a specific physical
           memory location.

       c)  All selectors have a size associated with them and attempts to
           access data at an offset greater than that size will result in
           a GPF.  This is one of the greatest strengths of a DOS Extender
           because most obscure bugs in real mode code occur when a wild
           pointer is used.  This will usually cause a GPF in protected
           mode because either the selector or offset value will be
           invalid.

       d)  Segment registers can be loaded with a selector value of 0 (a
           NULL selector), but never try to write to or read from a NULL
           selector.

       e)  Segment values in real mode always point to a physical address
           equal to the segment value multiplied by 16, but selector
           values in protected mode may point to anywhere in memory.  The
           CPMI contains services for obtaining protected mode selectors
           from real mode addresses.

   2)  You cannot execute code in a data segment and you cannot write to
       data in the code segment.

   3)  You may not directly issue real mode interrupts from protected
       mode.  The CPMI has services for calling real mode interrupts if
       you find it necessary.



   The CPMI.H header file
   ========================================================================

   Prototypes for all of the CPMI functions can be found in the CPMI.H
   header file, along with a few typedefs used by by the CPMI.  In
   addition, each .ASM source file contains a detailed function header
   that describes syntax and return value information.



   Writing Toolkit functions for protected mode
   ========================================================================

   Most Toolkit functions will work fine in protected mode with no
   modifications.  In some cases, however, the function may need to be
   altered to achieve protected mode compatibility.  To prevent a
   version-control nightmare, all Toolkit functions should be written such
   that the SAME CODE will work in both real and protected mode -- i.e.
   there SHOULD NOT be two separate versions of the same function.

   This is much easier than it might appear at first glance.  For example,
   consider the following function from version 2.0 of the Toolkit:

        CLIPPER FT_Alt( void )
        {
           _retl( ( int ) ( ( * ( char * ) 0x00000417 ) & 0x8 ) );

           return;
        }

   This function returns the state of the ALT key, and it works just fine
   in real mode.  In protected mode, however, it causes a GPF because a
   null selector is involved.  It can easily be fixed, though, by using
   the address 0040:0017 instead of 0000:0417.  The two addresses point to
   the exact same physical memory in real mode, and in protected mode the
   DOS extender provides a selector of 40h that corresponds to the real
   mode segment 40h.

   It won't always be so simple, of course.  In some cases it may be
   necessary to construct the code such that it works slightly differently
   depending on the CPU mode.  For example, suppose you wanted to retrieve
   the BIOS date stamp at F000:FFF5.  Making it compatible with both real
   and protected mode isn't hard when you use the CPMI services:

        #define DATEPTR ( ( char * ) 0xF000FFF5 ) )

        CLIPPER BIOSDate( void )
        {
           auto int isProtMode = cpmiIsProtected();
           auto char * cDate;

           if ( isProtMode )
           {
              FP_SEG( cDate ) = cpmiProtectedPtr( DATEPTR, 8 );
              FP_OFF( cDate ) = 0;
           }
           else
              cDate = DATEPTR;

           _retclen( cDate, 8 );

           if ( isProtMode ) cpmiFreeSelector( FP_SEG( cDate ) );

           return;
        }

   Given the ease with which it can be done, all Toolkit functions are
   required to work in either real or protected mode.  The CPMI API exists
   to help you accomplish this goal.  If you require further assistance,
   please contact the Toolkit librarian or the CPMI author.

This page created by ng2html v1.05, the Norton guide to HTML conversion utility. Written by Dave Pearson