General guidelines for converting a 16 bit driver to a 32 bit driver
using the Drv32 kit.

Author: David Azarewicz  Revised: 2020-Jul-09


Requirements
============

Drv32 drivers have the following segment layout. Note that all of the
data segments (including the 16 bit and 32 bit) are combined into one
DGROUP and that has a maximum size of 64K. This is required for
thunking. The 16 code segment and 32 bit code segments are separate so
the 32 bit code segment does not have a size limit. Of course, you can
allocate all the memory you want outside of the data segment. The
MemAlloc() functions can allocate up to 22 MB of memory (the heap) and
provide both 16 and 32 bit addresses. The D32VMAlloc() and D32AllocMem()
functions allocate kernel memory and can allocate an unlimited amount
of 32 bit accessible memory.

Segment                Class          Group
=======                =====          =====
_HEADER16              DATA           DGROUP
_DATA16                DATA           DGROUP
_ENDDATA16             ENDDS          DGROUP
CONST                  DATA           DGROUP
CONST2                 DATA           DGROUP
_DATA                  DATA           DGROUP
_BSS                   BSS            DGROUP
_ENDDATA32             BSS            DGROUP
_TEXT16                CODE           CGROUP16
_ENDTEXT16             CODE           CGROUP16
_TEXT                  CODE           CGROUP
_ENDTEXT32             CODE           CGROUP

The header module provides all the proper segment definitions and groupings
and must be linked in first.

For non-driver applications such as IFSs, the header segment and the 16 bit
size markers are not needed.

Segment                Class          Group
=======                =====          =====
_DATA16                DATA           DGROUP
CONST                  DATA           DGROUP
CONST2                 DATA           DGROUP
_DATA                  DATA           DGROUP
_BSS                   BSS            DGROUP
_ENDDATA32             BSS            DGROUP
_TEXT16                CODE           CGROUP16
_TEXT                  CODE           CGROUP
_ENDTEXT32             CODE           CGROUP

The GenInit module provides all the proper segment definitions and groupings
and should be linked in first.

* Remove all far keywords. Normal 32 bit pointers do not need far specified.
  Use the FAR16DATA macro for 16 bit pointers.

* Use the FAR16NULL macro instead of NULL for 16 bit pointers.

* All DevHelp functions must be changed to 32 bit functions:
  DevHelp_ProcBlock() -> KernBlock()
  DevHelp_ProcRun() -> KernWakeup()
  DevHelp_VirtToLin() -> Far16ToFlat()
  DevHelp_VMLock() -> KernVMLock()
  DevHelp_VMUnLock() -> KernVMUnLock()
  DevHelp_VMAlloc() -> D32VMAlloc() or D32AllocMem() or KernVMAlloc()
  DevHelp_InternalError() -> Dev32Help_InternalError()
  DevHelp_GetDOSVar() -> Dev32Help_GetDOSVar()
  DevHelp_Yield() -> Dev32Help_Yield()
  DevHelp_VerifyAccess() -> Not Available. See ValidateFar16Adr()
  DevHelp_RAS() -> KernRASSysTrace()

  *** If you think you need these functions, reexamine your code.
  *** These functions should not be needed by a 32 bit driver.
  DevHelp_AllocGDTSelector() -> Dev32Help_AllocGDTSelector()
  DevHelp_LinToGDTSelector() -> Dev32Help_LinToGDTSelector()
  DevHelp_FreeGDTSelector() -> Not Available
  DevHelp_PhysToGDTSelector() -> Dev32Help_PhysToGDTSel()

* All memory allocation and pointer manipulation must be addressed.

* Beware of impossible 32 bit -> 16 bit pointer conversions. For a
  32 bit -> 16 bit pointer conversion to work, the 32 bit pointer must
  point to memory on the stack, or in *your* data segment (see DGROUP
  requirements above). You can also get 16 bit pointers for the
  MemAlloc() allocated buffers using MemFar16Adr(). FlatToFar16() will
  *not* work on MemAlloc() pointers. Use MemFar16Adr() instead.
  Also you usually *cannot* convert a 16 bit -> 32 bit pointer and
  then convert that 32 bit pointer back to a 16 bit pointer.



Recommendations
===============

* Eliminate the use of all the pointer typedefs and macros. These confuse
  the code and can be wrong. So don't use PCHAR, PSHORT, PLONG, PUSHORT,
  PULONG, PVOID, PSZ, or any typedef or macro that defines a pointer. All
  of your pointers should be clearly defined in only 2 ways:
    type *pViarable; /* for 32 bit flat pointers */
    type FAR16DATA *f16Variable; /* for 16 bit far pointers */
  This keeps pointer mismatches/conversions clear and obvious. It also lets
  the compiler do the conversions automatically for you if you choose.

* Avoid repeated 16 bit -> 32 bit pointer conversions. Save both the 16
  bit pointer and the 32 bit pointer and use whichever one is needed from
  a local variable.

* Avoid 32 bit -> 16 bit pointer conversions whenever possible. These can
  be expensive conversions. Definitely avoid repeated 32->16 pointer
  conversions.

* Use D32VMAlloc() or D32AllocMem() to allocate 32 bit memory whenever
  16 bit pointers to the memory are not required. Only use MemAlloc()
  and MemAllocAlign() when 16 bit pointers to the memory are required.



Work in progress for IFS drivers
================================

A function will be provided for initializing the library:

  USHORT __cdecl GenInit(void FAR16DATA *DevHelp);

This is a 16 bit function to be called with the standard OS/2 calling syntax.
DS must be set to the current 16 bit data segment. You must pass the address
of the system's Device Helper function which is provided by the FS_INIT call.
This function may be called from ring 0 or ring 3.

Eventually I will provide a full thunking interface for all the IFS
functions, but for now you must call GenInit() as early as possible from
the FS_INIT function, and before you call any Dev32Help_ functions and
before you do any 32bit->16bit conversions with the FlatToFar16() function.
