LAN Device Driver Documentation
By IBM
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
About This Document
This document proposes extensions to the current Network Driver Interface Specification (NDIS) 2.0.1 dated October 5, 1990. These extensions are required in order for IBM* to properly implement the IEEE 802.2 CCB interface as an NDIS protocol driver. These extensions would not necessarily require a change to existing media access control (MAC) device drivers. In fact, these extensions are intended only for 802.5 type MAC device drivers. A MAC device driver can indicate that the extensions in this document are supported by setting the minor NDIS version to 02 in the common characteristics table.
The proposal would add a new primitive to the NDIS interface and also extend the MAC service specific characteristics table (SSC) and the MAC media specific statistics (MSS) for 802.5 Details of these extensions are given in the following sections.
Note: NDIS 2.0.1 is jointly authored by 3Com** and Microsoft.** The SSC and MSS are tables defined in the NDIS. The extensions to NDIS 2.0.1, as described in this document, are derived by IBM.
This document refers to the following publications for additional information:
- Microsoft/3Com LAN Manager** Network Driver Interface Specification (NDIS), Version 2.0.1, October 8, 1990.
- Microsoft LAN Manager Programmer's Guide for NDIS, Version 2.0.1, June 1990
- IBM LAN Technical Reference
1.0 New General Request to Modify OPEN Parms
1.0 New General Request to Modify OPEN Parms
Purpose: Modify Open Parameters PUSH WORD ProtID ;Module ID of Protocol PUSH WORD ReqHandle ;Unique handle for this request or 0 PUSH WORD OpenOptions ;New Open Options for adapter PUSH WORD 0 ;Pad parameter - must be 0 PUSH WORD 16 ;Opcodes for this request PUSH WORD MACDS ;DS of called MAC module Call Request Returns: 0x0000 SUCCESS 0x0002 REQUEST_QUEUED 0x0003 OUT_OF_RESOURCE 0x0007 INVALID_PARAMETER 0x0008 INVALID_FUNCTION 0x0009 NOT_SUPPORTED 0x00FF GENERAL_FAILURE
Description:
This command directs a MAC device driver to change the adapter specific OpenOptions on the adapter. For IBM Token-Ring compatible adapters, OpenOptions are defined in the IBM LAN Technical Reference Manual.
1.2 Change to Service Flags to Support ModifyOpenParms
Bit 17 of the Service flags in the MAC device driver SCC indicates if the MAC device driver supports the modification of the Open parameters with the new ModifyOpenParms NDIS primitive.
2.0 Proposed Changes to the MAC SSC
The MAC SSC will be extended to include a pointer to a new table.
Note: The pointer to this new table is included immediately following the Max number of data blocks in the current definition of the MAC SSC.
This new table has the following structure:
BYTE AdapterConfig (DIR. STATUS) BYTE Reserved BYTE(10) MicroCodeLevel (DIR.STATUS) DWORD AdapterParmsAddr (DIR.STATUS) DWORD AdapterMACAddr (DIR. STATUS) WORD SRAMAddress (DIR. INITIALIZE) WORD BringUps (DIR. INITIALIZE and DIR.OPEN.ADAPTER) WORD AdapterType (DIR. STATUS)
The previous values are needed to support the IBM IEEE 802.2 CCB interface DIR.STATUS and DIR.INITIALIZE commands. These commands are defined in the IBM LAN Technical Reference as follows:
Previous Value | New Value and Location |
AdapterConfig | adapter_config in DIR.STATUS |
MicroCodeLevel | microcode_level in DIR.STATUS |
AdapterParmAddr | adapter_parms_addr in DIR.STATUS |
AdapterMACAddr | adapter_mac_addr in DIR.STATUS |
SRAMAddress | SRAM_address in DIR.INITIALIZE |
BringUps | bring_ups in DIR.INTIALIZE and DIR.OPEN.ADAPTER |
AdapterType | adapter_type in DIR.STATUS |
Note that a protocol can determine if the MAC device driver supports this extended table format by looking at the minor NDIS version byte of the common characteristics table. This byte is set to 02 for this version. A MAC device driver may not need to support the extended SSC format but needs to support version 2.02 for some other reason (for example ModifyOpenParms). This can be done by setting the minor NDIS version byte of the CCT to 02 and setting the pointer to the previously defined structure to NULL.
Also note that even though link speed is already returned in the common characteristics table, it should also be returned in the AdapterConfig byte.
Certain adapter cards may not be able to support all of the fields in this structure. For these MAC device drivers, binary 0's can be inserted in those fields that are not supported.
3.0 Proposed Changes to the MAC 802.5 Media Specific Statistics
The MAC media specific statistics (MSS) are extended to include the following information:
WORD RingUtilizationMeasurement (DIR.STATUS)
Note: The fields defined here are included immediately following the number of underruns in the current definition of the MAC MSS.
The previous value is needed in order to support the IBM IEEE 802.2 CCB interface DIR.STATUS. It is defined in the IBM LAN Technical Reference as follows:
RingUtilizationMeasurement is ring utilization measurement in (DIR.STATUS)
Note that a protocol can determine if the MAC device driver supports this extended table format by looking at the minor NDIS version byte of the common characteristics table. This byte is set to 02 for this version. 'The 802.5 statistics structure version level is also 02 in the 802.5 MSS.
Note that if this counter is not supported, it must be set to FFFF.
4.0 Proposed Changes to the Status Indication General Request
An additional Status Indication is being proposed to inform the upper layers of status changes concerning the presence of the PCMCIA LAN adapters. Existing protocol stacks that do not support this new NDIS primitive will have to rely on existing NDIS support for error indications. For situations where the new Status Indication is not supported the existing Ring Status Status Indication of Lobe Wire Fault would be appropriate. The Status Indication is called AdapterPresence.
Purpose: Return a change in the Presence of a LAN Adapter. PUSH WORD MACID ;Module ID of MAC PUSH WORD Status ;New Adapter Status PUSH LPBYTE Indicate ;Virtual address if indicate flag PUSH WORD 6 ;Adapter Presences Indication PUSH WORD ProtDS ;DS of called protocol module Call Status Returns: 0x0000 SUCCESS
Called by LAN MAC drivers to indicate a change in the presence of a LAN Adapter. The status codes for the MAC drivers are encoded in a 16 bit mask, where the bits for the mask are defined as:
Bit | Meaning |
15 | Ejection Request |
14 | Ejection Complete |
13 | Insertion Request |
12 | Insertion Complete |
11 | Card Insertion |
10 | Card Removal |
9 | PM Resume(Reserved) |
8 | PM Suspend (Reserved) |
7-0 | Reserved |
For further details refer to the PCMCIA Card Services Interface Specification, Release 2.00 and Network Driver Interface Specification, Version 2.01.
Note: Currently, only the NetBEUI device driver supports these proposed extensions. This implementation in NetBEUI only supports the Card Insertion and Card Removal status codes. The Card Removal status code is reported as a Lobe Wire Fault to the application.
Notices
May, 1995
Issued by:
- IBM Corporation
- Personal Software Products
- 11400 Burnet Road
- Austin, Texas 78758
First Edition (May 1992)
Second Edition (May 1993)
Third Edition (May 1995)
The following paragraph does not apply to the United Kingdom or any country where such provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this statement may not apply to you.
This publication could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; these changes will be incorporated in new editions of the publication. IBM may make improvements and/or changes in the product(s) and/or program(s) described in this publication at any time.
It is possible that this publication may contain reference to, or information about, IBM products (machines and programs), programming, or services that are not announced in your country. Such references or information must not be construed to mean that IBM intends to announce such IBM products, programming, or services in your country.
Copyright Notices
© Copyright International Business Machines Corporation 1992, 1995. All rights reserved.
Note to U.S. Government Users - Documentation related to restricted rights - Use, duplication or disclosure is subject to restrictions set forth in GSA ADP Schedule Contract with IBM Corp.
Disclaimers
References in this publication to IBM products, programs, or services do not imply that IBM intends to make these available in all countries in which IBM operates. Any reference to an IBM product, program, or service is not intended to state or imply that only IBM's product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any of IBM's intellectual property rights or other legally protectible rights may be used instead of the IBM product, program, or service. Evaluation and verification of operation in conjunction with other products, programs, or services, except those expressly designated by IBM, are the user's responsibility.
IBM may have patents or pending patent applications covering subject matter in this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries, in writing, to the IBM Director of Commercial Relations, IBM Corporation, Purchase, NY 10577.
Trademarks
The following terms, denoted by an asterisk (*) in this publication, are trademarks of the IBM Corporation in the United States and/or other countries:
IBM | OS/2 |
The following terms, denoted by a double asterisk (**) in this publication, are trademarks of other companies as follows:
Microsoft | Microsoft Corporation |
Microsoft LAN Manager | Microsoft Corporation |
3Com | 3Com Corporation |
NDIS Implementation Information for IBM LAN Systems
OS/2 Messaging and National Language Support
Table of Contents
- About This Document
- 1.0 General Strategy
- 2.0 Standardized Services for Device Driver Message Display and Logging
- 2.1 Device Driver Initialization
- 2.2 Device Driver Strategy Time
- 3.0 Non-Device Interface to the LAN Transport Message Functions
- 3.1 Functional Description
- 3.2 Implementation
- 4.0 Data Structure Definitions and Return Codes
- 4.1 Message Parameter Block
- 4.2 DevIOCtl Returned Status Field: (DevIOClt Function 1)
- 4.3 IDCInformation Request Packet: (DevlOCtl Function's 2 & 3)
- 4.4 Default Path Information Request Packet: (DevlOCtl Function 7)
- 4.5 Possible Return Codes
- 5.0 Installation/Configuration
- 5.1 CONFIG.SYS Entries
- 5.2 Configuring the Override for the Default Path Name
- 5.3 Other Configuration Parameters to the Messaging Support Driver
- Notices
[[[#Sec10|next]]][[[#toc|parent]]][[[#toc|TOC]]]
About This Document
This document describes the interface for device drivers ring-3 application, and information about the specific implementation as it pertains to the message strategy of and National Language Support (NLS) for an IBM* Network Driver Interface Specification (NDIS) 2.01 device driver, as implemented in IBM* LAN Adapter and Protocol Support*. This document is not meant to be a tutorial; it is assumed that the user has knowledge of the rules and procedures on calls made to device drivers using both the DosDevlOCtl interface and the InterDevice Driver Communications (IDC) entry point. The information on these topics is presented here in a reference or summary manner.
Note: NDIS 2.0.1 is jointly authored by the 3Com*** Corporation and the Microsoft** Corporation.
The following publications provide additional information:
- 3Com/Microsoft LAN Manager** Network Driver Interface Specification (NDlS), Version 2.0.1, October 8, 1990
- Microsoft LAN Manager, Programmer's Guide for NDIS, Version 2.0. 1, June, 1990
- NDIS Implementation Information for IBM LAN Systems, Extended NIF Format, May, 1993
- NDIS implementation Information for IBM LAN Systems, NDIS Extensions, May, 1993
1.0 General Strategy
- All messages will be kept in a file separate from the application. They are separated from the executable code to enable NLS translation of messages into different languages without altering the calling program. It is strongly recommended that a help message file be included as a companion for the message file.
Refer to the OS/2 Technical Reference for the format of message text and the output file of MKMSGF utility.
- When errors are encountered by an NDIS driver during the IPLing of the machine, a message describing the error should be logged into a message log file and displayed to the console.
- If the LAN message device driver (LANMSGDD.OS2) is installed, and its companion DLL file (LANMSGDL.DLL) is available, then messages describing any errors can be logged in the message log file (LANMSGDD.LOG) and displayed to the console. This message log display interface is compatible with First Failure Support Technology/2 (FFST/2) and can be used at both IPL and run time.
The detailed LAN message device driver interface is described in Chapter 2, and the interface for ring-3 applications is described in Chapter 3. - The message and log files are assumed to be in the \IBMCOM subdirectory, unless changed by the user.
2.0 Standardized Services for Device Driver Message Display and Logging
This section describes the input parameters and calling conventions for the LAN message device driver (LANMSGDD.OS2). This piece of the system runs at privilege level zero and can be accessed by other device drivers both during their initialization and strategy lifetime. The interface basically enables a message to be retrieved from an NLS translatable message file and written to a message log file, and optionally displayed to the console. This means ring-0 message logging is now possible. The intent of this ring-0 service is not to enforce a standardization upon device drivers needing messaging service but rather to offer an interface that facilitates problem solving at the device driver or system level.
The interface is written to be compatible with the First Failure Support Technology/2 (FFST/2) interface but will still provide messaging services if FFST/2 is not available on the system. Thus, some parameters that may seem redundant for an application running with ring-3 privilege level are nevertheless required input to FFST/2.
2.1 Device Driver Initialization
During a device driver initialization period, it runs as a pseudo ring-3 application. During this time, it has access to a subset of DOS calls, including DosOpen, DosWrite, DosGetMessage and DosPutMessage. Using these APIs at initialization time, a device driver can display and write its messages to a log without assistance. This is the method most device drivers are currently using. However, this ability is lost after the device completes initialization.
A ring-3 entry point to the messaging support driver is provided solely for the sake of standardization and convenience to the device drivers it services. It exists so that all messages in a system can be logged to the same file without requiring knowledge about the log file name or location. It also alleviates the need for a device driver to open, go to the end of the file, write the record, and close the file for every message logged. Thus, this ring-3 interface can eliminate redundant code that would otherwise be needed in each device driver.
In order for messaging services to be available to other device drivers at IPL time, it is required that the LANMSGDD.OS2 module load prior to the calling device. This is easily accomplished by placing the DEVICE= statement for LANMSGDD.OS2 before the calling device in CONFIG.SYS. This ensures that when a device driver enters it initialization period, the messaging support driver is already loaded. As such, the messaging support driver has already made its transition from ring-3 to ring-0. The DOS services to which the initializing device driver has access are now unavailable to the messaging support driver. Its only access to these functions is through its ring-3 thread started by LANMSGEX.EXE. This thread, however, is not available until all device drivers specified in CONFIG.SYS have completed loading. To handle this, LANMSGDD.OS2 uses a queue for incoming message requests until the ring-3 thread is ready.
When the messaging support driver is called, it queues the request until the ring-3 services provided by LANMSGDL.DLL are available. For message logging, this is not a problem since the user cannot view the log until after IPL. However, messages that are to be displayed to the console during device driver initialization will experience a delay until the queue is processed. Therefore, if a device driver has a banner or logo it wants displayed during its initialization period, it may be preferable to use an API such as DosWrite to generate standard output.
2.1.1 Implementation
The messaging support driver ring-3 entry point is implemented using a general DosDevIOCtl call. Before DosDevIOCtl call can be made, the calling device driver will need a file handle by issuing a DosOpen to the messaging device driver. The name to use on the DosOpen call is \LANMSG$$. Even though it is not currently required, it is suggested that the full path and file name, \DEV\LANMSG$$, be used on the DosOpen. There was once an OS/2 1.2 requirement that the \DEV path be used to open a device driver. This requirement was dropped, but use of the path does work and it may prevent a code modification in some future release.
2.1.2 Functions Provided
Several messaging functions are provided to device driver applications when they run at privilege-level 3. To invoke these functions, the DosDevIOCtl function category 90h (the message device category code) must be used. This category will generate a general DevIOCtl to the messaging support driver. Four message service requests are provided through this category depending upon the DosDevIOCtl function code passed. The functions provided are:
Function 01 = Request messaging services. Function 02 = Request LANMSGDD IDC entry point. Function 03 = Combine requests 01 and 02 in one DevIOCtl call.
Function 07 = Request Default Message Path.
2.1.2.1 Function 01: Message Service Request
Function 01 will generate a general request for messaging services. The specifics of the request are contained in the input parameters passed in the DosDevIOCtl parameter buffer. This field is a far pointer (DWORD) to the message parameter block. This parameter block contains the component name of the device driver requesting services, the message number to access, the type of message, a display option, the full path and file name of the message input file, the output log file, and any insertion strings required for the message. A detailed description of the message parameter block is contained in 4.0, "Data Structure Definitions and Return Codes". The only required input parameter in the message parameter block is the message number identifier. All others are optional.
Output parameters are passed back to the calling routine in the DosDevIOCtl data buffer field. This field is a far pointer (DWORD) to a status variable. This variable is a WORD and will contain the return code on the success of the request. This field is needed since AX will contain the return code of the DosDevIOCtl call itself and is required on all message DosDevIOCtl calls. Device driver return codes are detailed in 4.0, "Data Structure Definitions and Retum Codes".
2.1.2.2 Function 02: Message IDC Information Request
This function allows a device driver to gain access to the message device driver ring-0 protect mode code segment entry point and data segment. This function alleviates the need for a device driver to issue an AttachDD during its ring-0 strategy time. It is important to remember that although one has the ring-0 entry point at its initialization time, a device driver may not use it until it has made its ring-0 transition.
There are no input parameters other than the function code passed on the DosDevIOCtl. Thus, the DosDevIOCtl parameter buffer field is null. Output is passed back in the data buffer area of the DosDevIOCtl. The data buffer must point the IDC information request packet. The first WORD of the packet contains the required status of the request. This is followed by a DOUBLE WORD, which contains the code segment and offset of the message device driver ring-0 entry point. The last field is a WORD, which contains the data segment of the Messaging Support Driver. A description of the IDC information request packet is contained in 4.0, "Data Structure Definitions and Return Codes" .
2.1.2.3 Function 03: Combine Functions 01 and 02
This function is provide solely for the convenience of the calling device driver. It keeps the caller from having to make two separate IOCtl's. Required input and output parameters for this function are a combination of functions
2.1.2.4 Function 07: Request Default Path
There is a hard-coded path where the messaging support driver (LANMSGDD.OS2) expects to find the default input message file, LT0.MSG, and will create the default output file, LANTRAN.LOG. This default path is \IBMCOM. Although the names of the default message file and log files usually do not need to be changed, they can be overridden using the input parameters passed in the message parameter block. The default path can be overridden using an input parameter on the DEVICE = statement for LANMSGDD.OS2 in CONFIG.SYS. This function is provided to enable device drivers to access the current default path. Refer to 5.0, "Installation/Configuration" for details.
Like Function 02, this function has no input parameter except the DosDevIOCtl function number itself. The DosDevIOCtl parameter buffer field is, therefore, null. The output of the request, like the other functions, is resumed through the DosDevIOCtl data field which points to the default path information request packet. The first WORD of the packet contains the status of this request. The next field in the packet contains a 32-bit pointer to a buffer where it will copy the full path and filename. Even though the default file name, LT0.MSG, can not be changed, the message device driver returns the full path and file name of the default message file. The next WORD in the packet holds the length of the path portion of the name only. Currently the maximum path length that the messaging support driver uses is 250 bytes.
The usefulness of this function lies in its ability to allow applications that do not use the default message file to query the messaging support device driver to obtain the current default path. This path is where the device driver can expect to find its message file. The application can then replace the default message file name with its own message file name. Accordingly, applications can keep their own message and log files in a common directory other than \IBMCOM. It may also prevent a device driver from having to define its own input parameter for the same purpose.
2.1.3 Calling Conventions and Input Parameters for the DosDevIOCtl Entry Point
(OS/2 creates a general DevIOCtl) Function category: 90h = Message device category code. Function code: 01 = Request messaging services. 02 = Request LANMSGDD IDC entry point. 03 = Combine r; Pass address if data packet, push OFFSET Msg_Status ; offset to status field push ds ; PASS PARMLIST , offset to push OFFSET Msg_Params ; message parameter block. push 1 ; Function code (message request) push 90h ; Messaging category push Msg_DDHand ; Handle to LANMSG$$ from DosOpen. call DOSDEVIOCTL cmp Ax,0 ; DevIOCTL SUCCESS? jne Out_Err ; No. cmp Msg_Status,0 ; Message request successful? jne Out_Err ; No.
2.2 Device Driver Strategy Time
The ring-0 interface (IDC or device driver strategy entry point) can be obtained using an AttachDD call or through a DevIOCtl, function 2 or 3, call during a device driver initialization.
2.2.1 Implementation
Calls to this entry point give a device driver access to the general messaging services provided by the messaging support driver. This entry point provides the equivalent functionality as that obtained the DosDevIOCtl function 02 call. Once the IDC entry point is obtained, only two parameters are required. The first parameter is a WORD value of 1. This value signifies that a device driver is requesting messaging services. The second parameter is a far (32-bit) pointer to the message parameter block. This is the same input block passed in the parameter buffer on the DosDevIOCtl call for function 02. Finally, AX will contain the same returned status code as that recorded in the data buffer Area of the function 02 DosDevIOCtl call.
2.2.2 Calling Conventions and Input Parameters for the IDC Entry Point
A list of the IDC, (inter-device communication or ring-0) input parameters and return code follow:
IDC invocation code: 0x0001 = Messaging function code. Message parameter block: A far pointer to the message parameter block Return code: On return, AX contains the same code as that logged in the IOCTL status field located in the DevIOCTL's data buffer Area.
2.2.3 IDC Entry Example
Note: If a DosDevIOCTl requesting the message device driver IDC entry point was not issued, an ATTACHDD is first required to get it. The calling application is also required to establish LANMSGDD DS before the call.
push es ; PASS PARMLIST, offset to push OFFSET Msg_Params ; message parameter block. push 1 ; Pass message IDC invocation. call DWORD ptr es:"Msg_CS" ; Call the MessageDD cmp AX,0 ; Success? jne OutMsg_Err ; No.
Note: When calling to the IDC entry point, the calling routine is assumed to have set up LANMSGDD data selector into DS prior to the call.
3.0 Non-Device Interface to the LAN Transport Message Functions
Following are a functional description and an implementation of the non-device interface to the message functions.
3.1 Functional Description
An additional entry point into the LAN transport message services has been defined using a dynamic link library (DLL). This entry point is available only after device driver initialization at IPL time. A ring-3 thread holds the DLL in memory for quick access to the entry point. The file itself is LANMSGDL.DLL, and its thread is LANMSGEX.EXE. Functionally, this entry point (MRMSG) provides access to the same general messaging services as those provided by both the DevIOCtl Function 01 entry and the IDC entry. In fact, a ring-3 application could call the messaging support device driver DevIOCtl entry and thereby gain access to all of its defined IOCtl functions. This interface provides a more direct access to the messaging function and is implemented solely for the convenience of an application.
3.2 Implementation
The non-device driver entry point is provided for ring-3 applications as a direct interface into the message dynamic link routine, LANMSGDL.DLL. It is not dependent upon the messaging support driver or its ring-3 EXE file, LANMSGEX.EXE, for existence. It operates like any DLL, from the thread of the calling routine. Actually, it is the same interface the LANMSGEX.EXE routine uses to output its own messages. It has been externalized for the convenience of any ring-3 application wanting to use it.
The message DLL routine contains all the logic for outputting a message to the console/log file or to FFST/2. This routine also determines if FFST/2 is present and available. It reformats the input parameters according to the interface being accessed. If FFST/2 is installed but not initialized, a warning message is displayed and logged, but no further attempt is made to access FFST/2 until the next IPL.
3.2.1 Input Parameters
Input to the routine is very similar to the IDC entry point parameters. Its first input parameter is a FAR pointer to the same message parameter block defined for the other two interfaces. See the description of the message parameter block in 4.0, "Data Structure Definitions and Return Codes". The second parameter is a WORD value that acts as an FFST/2 option flag. It allows an application to specify whether output to FFST/2 is desired. If the value passed is zero, the DLL precludes the use of the FFST/2 interface. If the value is set to 1, the routine uses FFST/2 services if they are available. The final parameter is a DWORD and is reserved. As such it must be 0. A list of the input parameters follows:
Message parameter block: A far pointer to the message parameter block. FFST/2 Options Flag: 0x0000 = Do not use FFST/2 0x0001 = Use FFST/2 interface if available. Reserved: DWORD value of all 0's.
3.2.2 Calling Conventions
The entry point label name to the Non-DD ring-3 interface is MRMSG. Either of the following OS/2 DLL linking methods can be used to gain access to this entry point. Each method for linking to MRMSG is demonstrated.
3.2.2.1 Linking Method:
This first example has only a requirement to include an IMPORT statement for LANMSGDL.MRMSG in the link deflation file.
Example - Method 1:
MASM external reference in source program: EXTRN MRMSG : FAR ; DLL message output routine. Linking example: LINK Appl.OBJ,Appl.exe,,Appl.MAP,doscalls,Appl.DEF /NOD/NOT/MAP; Example OS/2 definition file: NAME APPL WINDOWCOMPAT PROTMODE DESCRIPTION 'APPL ANY RING-3 APPLICATION' STACKSIZE 4096 IMPORTS LANMSGDL.MRMSG
The second method does not require any external reference definitions or DEPORT definition. It makes use of OS/2 DosLoadModule and DosGetProcAddr. For a discussion of this method see the 0S/2 Programmer's Reference. A sample of this method follows.
Example Method 2:
;;; Now load DLL module push SEG ObjBuf ;Addr to buffer for the failing module push OFFSET ObjBuf push ObjLen ;Above's buffer length push SEG LanMSgMod ;Pointer to module name 'LAMSGDL' push OFFSET LanMsgMod push Seg LanMsgHand ;Pointer to word value for Handle push OFFSET LanMsgHand call DosLOADMODULE or ax,ax jnz Error_End ;Bad return; cannot call module ;;; Now get module entry point push LanMsgHand ;Handle to DLL module push SEG LanMsgProc ;Pointer to procedure name 'MRMSG' push OFFSET LanMSGProc push SEG MRMSG ;Ptr to DWORD to contain entry point push OFFSET MRMSG call DOSGETPROCADDR or ax,ax jnz Error_End ;Bad RC; do not call module
3.2.2.2 Parameter Passing on Calling Sequence
An example of the calling sequence to the MRMSG interface follows:
;;;; Call message DLL here push SEG MsgData ; Pass msg control block push OFFSET MsgData push 1 ; Use FFST/2 if available push 0 ; First WORD of 0'st push 0 ; Second WORD of 0's call MRMSG ; Far call to output msg or ax,ax ; Error? jne Error_End ; Yes.
4.0 Data Structure Definitions and Return Codes
Data structure definitions are provided for the message parameter block, the DevIOCtl resumed status field, the IDC information request packet, and the default path information packet. Return codes are also listed.
4.1 Message Parameter Block
The message parameter block is the basic input parameter structure used to request messaging services using both the DevIOCtl and the IDC entry points for device drivers and the non-device driver entry point for ring-3 applications. It is composed of the following fields (in order).
- COMPONENT_ID - Far pointer (double word) to an 8-byte string that identifies the calling component, for example, the name of the device driver requesting messaging services. If null, the message contains information about who originated the message. If FFST/2 is installed, this field is used as the subcomponent name. (OPTIONAL)
- IV_ARRAY - Far pointer to an array of far pointers, from 0-9, that point to a 0-terminated string text used as message text insertion data. (If null, no insertion data exists.) (OPTIONAL)
- IV_Number - Word value indicating the number of text insertion pointers found in the IV_Array field. Values 0 - 9 (0 means no insertion data exists). (OPTIONAL)
- MESSAGE_Num - Word value used to hold the message number ID of the desired message. (REQUIRED)
- Message_File - Far pointer to a null-terminated string identifying the path and message file name that contains the message text. If null, the default is used. (OPTIONAL)
- Message_Type - Afford value used for the following types. (OPTIONAL)
4500h - ('E'00) denotes an error message.
5700h - ('W'00) denotes a warning message. 4900h - ('I'00) denotes an informational message. 0000h - (''00) denotes an unclassified message.
- Display_Flag - Word value indicating the console display option. (OPTIONAL)
Possible values include:
False (0) - do not display, even if error type.
True (1) - display to console.
- Log_File - Far pointer to an alternate message log path and file name where the messages will be written. If null, the default is used. (OPTIONAL)
4.2 DevIOCtl Returned Status Field: (DevIOClt Function 1)
When requesting message services of DosDevIOCtl function 1 to the message device driver, the data buffer field on the IOCTL call must point to a WORD value. This value contains the status of the request on IOCTL completion. This status field is required on all DevIOCtl calls to the messaging device driver.
Returned status of request - Word (REQUIRED for all DevIOCtl's)
4.3 IDC Information Request Packet: (DevIOCtl Function's 2 & 3)
The ring-0 Information Request Packet is used for DevIOCtl output, i.e., passed in the Data Buffer area on the DosDevIOCtl call. The packet's structure is defined below:
Returned status of request - Word (REQUIRED for all DevIOCtl's) IDC/ring-0 entry point - Double word (REQUIRED for IOCTL functions 2 and 3) Ring-0 data segment - Word (REQUIRED for IOCTL functions 2 and 3)
4.4 Default Path Information Request Packet: (DevIOCtl Function 7)
The ring-0 path information request packet can be used to determine what the current default message path is. The packet is used as output, that is, output passed in the data buffer area on the DosDevIOCtl call. The request packet is defined as follows:
Returned status of request - Word (REQUIRED) Default path buffer address - Double word pointer (REQUIRED) Length of path name - Word (REQUIRED)
4.5 Possible Return Codes
Possible return codes for all message entry points follow.
Note: This list is not intended to be exhaustive. Other unexpected DevHelp or OS/2 system calls may also be received.
0x0000 - Request has been accepted. 0x0001 - ERROR INVALID FUNCTION (Bad IDC invocation) 0x0002 - ERROR FILE NOT FOUND 0x0008 - ERROR NOT ENOUGH_MEMORY (Not enough internal resources to satisfy request) 0x013C - ERROR MR_MSG_TOO_LONG (Message too long for message buffer) 0x013D - ERROR MR_MID_NOT_FOUND (Message number not found) 0x013E - ERROR MR_UN_ ACC_MSGT (Unable to access message file) 0x013F - ERROR MR_INV_MSGT_FORMAT (Invalid message file format) 0x0140 - ERROR_MR_INV_IVCOUNT (Invalid insertion variable count) 0x0141 - ERROR_MR_UN_PERFORM (Unable to perform function)
5.0 Installation/Configuration
There are three separate modules required for messaging services. The ring-0 executable filename of the device driver is LANMSGDD.OS2. The device driver maintains a detached ring-3 thread, which it uses to gain access to DOS kernel services. The ring-3 executable file name is LANMSGEX.EXE. This ring-3 thread also requires the ring-3 message DLL file LANMSGDL.DLL.
5.1 CONFIG.SYS Entries
The messaging device driver is loaded by a DEVICE = statement in the CONFIG.SYS file. This statement should be inserted into the CONFIG.SYS before any other LAN related device driver statements.
In order to provide the detached ring-3 thread, a RUN = statement for the LANMSGEX.EXE file is a so required. Additionally, in order to gain access to the messaging DLL file, a path name where the LANMSGDL.DLL exists must be entered on the LIBPATH statement in the CONFIG.SYS file.
Assuming the Lan Transport Services reside in the \IBMCOM subdirectory, the entries in CONFIG.SYS should be the following:
LIBPATH=C:\OS2\DLL;C:\IBMCOM; . . . DEVICE=C:\IBMCOM\LANMSGDD.OS2 RUN=C:\IBMCOM\LANMSGEX.EXE
5.2 Configuring the Override for the Default Path Name
The default path where the messaging support driver expects to find the message file and where it will place the log file is the IBMCOM directory. The default path can be overridden by placing an optional /I parameter on the LANMSGDD's DEVICE = statement in the CONFIG.SYS file. An example follows:
DEVICE=C:\IBMCOM\LANMSGDD.0S2 /I :C:\IBMLAN
The /I parameter requires the drive and directory where the message file and message log reside. A terminating backlash on the override string must not be included. If the drive is omitted, the current root is assumed.
The default message and log file names are LT0.MSG and LANTRAN.LOG. These defaults can be overridden only by using the runtime interface input parameters to the messaging support driver. If the C:\IBMCOM default is desired, the /I parameter can be omitted.
5.2.1 Search Path Rules
Rules for message and log file search paths follow:
- If the message file does not exist in the default path but the path exists, the device driver searches the root directory for the input message file but still logs all messages using the original default path.
- If the default path does not exist, the root directory is searched for the message file. If found, the default path is changed to the root and the log file is also placed there.
- If the message file cannot be found in the default or the root directory, the device driver fails to install, and the log file is created in the root directory.
5.3 Other Configuration Parameters to the Messaging Support Driver
There are two other parameters which can effect the messaging support driver functioning. Like the default path override, these too are placed on the DEVICE = statement of the LanMsgDD device driver. The /S parameter disables the display function, while the /P disables the pause-on-error function.
If the customer wants to disable all messaging display from the messaging support driver, the /S parameter can be inserted at the end of the DEVICE= statement for LANMSGDD.OS2 in the CONFIG.SYS file. This will not affect messages that are displayed independently by a device driver at initialization time but will disable any message sent to the messaging support driver with the display option on. The messages will continued to be logged.
Currently if a message is received by the messaging support driver with an error type set and the display option on, the message is displayed and with a pause-on-error message. This pause-on-error requires operator intervention to continue. By default the pause-on-error option is on. To disable pause-on-error in the messaging support driver, the /P option can be inserted at the end of the DEVICE= statement for LANMSGDD.OS2 in CONFIG.SYS.
These parameters can be inserted in any order and may be entered in either upper or lower case.
Notices
May, 1993
Issued by:
- IBM Corporation
- Personal Software Products
- 11400 Burnet Road
- Austin, Texas 78758
First Edition (May 1992)
Second Edition (May 1993)
The following paragraph does not apply to the United Kingdom or any country where such provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this statement may not apply to you.
This publication could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; these changes will be incorporated in new editions of the publication. IBM may make improvements and/or changes in the product(s) and/or program(s) described in this publication at any time.
It is possible that this publication may contain reference to, or information about, IBM products (machines and programs), programming, or services that are not announced in your country. Such references or information must not be construed to mean that IBM intends to announce such IBM products, programming, or services in your country.
Copyright Notices
© Copyright International Business Machines Corporation 1992, 1993. All rights reserved.
Note to U.S. Government Users - Documentation related to restricted rights - Use, duplication or disclosure is subject to restrictions set forth in GSA ADP Schedule Contract with IBM Corp.
Disclaimers
References in this publication to IBM products, programs, or services do not imply that IBM intends to make these available in all countries in which IBM operates. Any reference to an IBM product, program, or service is not intended to state or imply that only IBM's product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any of IBM's intellectual property rights or other legally protectible rights may be used instead of the IBM product, program, or service. Evaluation and verification of operation in conjunction with other products, programs, or services, except those expressly designated by IBM, are the user's responsibility.
IBM may have patents or pending patent applications covering subject matter in this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries, in writing, to the IBM Director of Commercial Relations, IBM Corporation, Purchase, NY 10577.
Trademarks
The following terms, denoted by an asterisk (*) in this publication, are trademarks of the IBM Corporation in the United States and/or other countries:
IBM | OS/2 |
The following terms, denoted by a double asterisk (**) in this publication, are trademarks of other companies as follows:
3Com | 3Com Corporation |
Microsoft LAN Manager | Microsoft Corporation |
NDIS Driver Developer's Tool Kit
for OS/2 and DOS
Programmer's Guide
Table of Contents
- Preface
- Chapter1. Overview
- Chapter 2. OS/2 Device Drivers
- Chapter 3. DOS Device Drivers
- Chapter 4. Writing a Media Access Control Driver
- Notices
[[[#HowUseThisManual|next]]][[[#toc|parent]]][[[#toc|TOC]]]
Preface
How to Use This Manual
How to Use This Manual
Audience
The principal audience for this manual is developers of NDIS Media Access Control (MAC) drivers for both DOS and OS/2. It is assumed that the reader is an experienced system programmer, familiar with the operating system, x86 programming, and system internals. Experience with networking and/or device drivers is highly recommended. Familiarity with NDIS, while helpful, is not assumed.
Content
This manual contains guidelines for writing an NDIS MAC driver. It is organized into four chapters. Chapter 1, Overview, contains general background information on device drivers, NDIS, and MAC drivers. Chapter 2, OS/2 Device Drivers, contains OS/2 specific information. Chapter 3, DOS Device Drivers, contains DOS specific information, from the point of view of the differences between DOS and OS/2 drivers. Finally Chapter 4, Writing a Media Access Control Driver, gives guidelines and examples useful for writing your MAC driver.
Result
The intended result of this manual is to aid your driver development.
Notational Conventions
The following notational conventions are used in this manual
- Hexadecimal (base 16) numbers are given in the form 0xdd, 0xdddd, etc.
For example, 0x28 is hexadecimal for the decimal number 40. - File names are given in all capital letters. Hence CONFIG.SYS stands for the file named CONFIG.SYS.
- Code examples are given in Courier type face.
NDIS
NDIS details an internal architecture for network drivers. Drivers are divided into two categories: Media Access Control (MAC) drivers and Protocol drivers. MAC drivers directly control network adapter cards, while protocol drivers interface with the operating system and/or applications. The NDIS details the responsibilities of both types of drivers as well as the interface between them. For more information on NDIS, see the publications: 3Com/Microsoft LAN Manager Network Driver Interface Specification 2.0.1 and NDIS Implementation Information for IBM LAN Systems, NDIS Extensions.
Finding Further Information
Further information can be found in the following document:
If you already have the LAN Technical Reference, you need to order the following document:
Note: Once the Supplement is available, it will ship with orders of the LAN Technical Reference.
Chapter 1. Overview
OS/2 and DOS use specialized software, known as device drivers, to manage input and output. Examples are screen display, keyboard or mouse input, printer output, floppy or hard drive file input/output, and network adapter input/output. Each device driver is responsible for the interface between the device (that is, its controller) and the operating system.
Types of Device Drivers
Each device driver falls into one of two distinct categories, character drivers or block drivers, depending upon its device. Block drivers manage random access devices, such as disc drives, that support logical units and a directory structure. Character drivers manage all other devices, including network adapter cards. We will be concerned with character drivers.
Device drivers are further authorized into base drivers and installable drivers. Base drivers handle the basic system input/output and are usually considered part of the operating system. We will not be concerned with base drivers. Installable drivers handle all other input/output functions.
Installable Device Drivers
Installable device drivers are loaded at system initiation time. The driver initialization thread reads the CONFIG.SYS file and loads and initializes the drivers specified in the "DEVICE=" statements on a first-read-first-loaded basis.
Drivers are loaded into low memory and must consist of a data segment followed by a code segment. Additional data or code segments, if present, will be loaded into high memory.
Parts of a Device Driver
Device drivers consist of from two to five components as follows:
- Device Driver Header (required). The first item in the driver's initial data segment is the device driver header. The header specifies device attributes and driver entry points.
- Strategy Routine (required). System communication with device drivers is accomplished by calling the driver's strategy routine. System requests include initialization and, for most device drivers, input/output requests.
- (Hardware) Interrupt Routine (recommended). OS/2 device drivers usually service hardware requests by means of hardware interrupts.
- Software Interrupt Handler (optional). DOS device drivers usually service hardware requests by means of software interrupts. OS/2 drivers may contain a software interrupt handle for backwards compatibility with DOS.
- Timer Handler (optional). OS/2 device drivers may specify a timer entry point which will be called by the system every 31.25 milliseconds.
Real Versus Protected Mode
OS/2 can emulate DOS, running DOS applications in the "DOS Compatibility Box". While in this mode, the processor emulates the behavior of the 8088 and 8086 chips by running in real mode. Otherwise the processor runs in protected mode.
While in real mode, the processor interprets the CS, DS, ES, and SS registers as segment registers, in protected mode they are selector registers. That is to say, in real mode 20-bit physical addresses are split into an high-order, 16-bit segment and a low-order, 4-bit offset. While in protected mode, address are virtual and consist of a 16-bit selector (whose three low order bits are ignored) and a 16-bit offset. The selector references a position in the appropriate (local or global) descriptor table (LDT or GDT).
Privilege Levels
While OS/2 is in protected mode, processes (and their threads) have a privilege level or ring number. The privilege level of a process determines its access to descriptor tables. Applications run at Ring 3, and can only access their own local descriptor table. The operating system runs at Ring 0, or kernel mode and can access both local and global descriptor tables.
Device drivers, however, initialize at Ring 3 (as do most applications) and run at Ring 0, to have greater access to the kernel and to hardware.
Introduction to NDIS
Network device drivers were traditionally large, monolithic drivers, containing code for protocols (the language of the network) as well as network hardware. Traditional drivers were difficult to write, had less flexibility, were harder to upgrade, and didn't support multiple protocols. A fully functional monolithic network driver would have to have the ability to interface with every protocol available.
A modular approach to protocol handling (in which only those protocols required are loaded) is a much more efficient use of system memory. The Network Device Interface Specification (NDIS) was developed to eliminate the need for multiple protocols within a single driver. Under NDIS, protocol handling is completely separated from hardware manipulation. NDIS replaces the traditional network driver with two distinct types of installable character drivers: protocol drivers and Media Access Control (MAC) drivers.
NDIS protocol drivers do not manipulate network hardware - they handle the various network data formats. MAC drivers handle the hardware. Working together, these two driver types replace the large monolithic network driver. As a result, protocol and hardware handling drivers are modular and streamlined. Protocol and MAC drivers, as a group, are called NDIS device drivers
The NDIS describes the functionality that both protocol and MAC drivers must provide for each other. The specification also describes a standard network driver interface for the two types (MAC and protocol) of NDIS device drivers
The interface includes a Protocol Manager to help organize configuration data and to bind the various modules together.
NDIS device drivers may choose to run under both OS/2 and DOS. NDIS drivers provide access to many kinds of complex protocols under multiple hardware configurations.
NDIS and the OSI Reference Model
The International Standards Organization, in an effort to standardize networks created the Open Systems Interconnection (OSI) reference model. In the OSI model, network software is thought of as a system of layers with each layer representing a particular task. The OSI model defines seven layers of networking tasks as follows
The lower portion of an NDIS protocol driver functions in the upper portion of the data link layer, above the network device driver interface. The upper portion of an NDIS protocol driver may reside anywhere from the data link to the application layer of the OSI model.
The device driver interface described in the NDIS specification functions within the data link layer of the OSI reference model.
NDIS MAC drivers are implemented at the bottom portion of the data link layer. MAC drivers may work with any physical media: PC Network, Token-Ring, ArcNet, etc. IBM protocol drivers support 802.3 or DIX (EtherNet) and 802.5 (Token-Ring) networks.
The Protocol Manager
The network device driver interface is implemented through a Protocol Manager used to coordinate connections (bindings) between modules. When an NDIS protocol or MAC driver loads and initializes, it passes to the Protocol Manager a pointer to an internal characteristics table that includes the module's name and entry points. Protocol drivers also pass a list of MAC drivers with which they wish to bind. The Protocol Manager reads the protocol driver's bindings list and helps the protocol driver to exchange information with each MAC driver in the list. The information exchanged consists of pointers to each other's characteristics tables. The exchanged entry point information allows protocol and MAC drivers to exchange characteristics tables and communicate directly with one another.
VECTOR
While a protocol driver may bind to multiple MAC drivers, each MAC driver must bind to one, and only one, protocol driver. To allow a MAC driver to bind to multiple protocol drivers or to allow a protocol driver to be dynamically loaded and unloaded, the Protocol Manager provides an additional module known as VECTOR. The VECTOR module shields a MAC driver from these details, allowing the MAC driver to be written as if there were always a single protocol driver bound to it.
Media Access Control Drivers
MAC drivers provide low-level access to network adapters. MAC drivers are loaded at system initialization time and are static - that is, they may not be removed from memory. The primary function of a MAC driver is to transmit and receive packets. Secondarily, the MAC driver also provides some basic adapter management functions.
Parts of a MAC Device Driver
Like other device drivers. an NDIS MAC driver contains the following components:
- Header
- Strategy Routine
- Initialization Routine
- Interrupt Routine
Additionally, an NDIS MAC driver must contain entry points for the following seven, NDIS-specific, entry points:
- System Request Routine
- General Request Routine
- TransmitChain Routine
- TransferData Routine
- ReceiveRelease Routine
- IndicationOff Routine
- IndicationOn Routine
Finally, an NDIS MAC driver must contain the following data structures:
- Common Characteristics Table
- Service-Specific Characteristics Table
- Service-Specific Status Table
- Upper Dispatch Table
How a MAC Device Driver Works
The sole purpose of the Strategy Routine in an NDIS MAC driver is to handle load-time initialization of the driver. Later the Protocol Manager directs NDIS drivers to exchange common characteristics table addresses with the drivers they bind to. Chained off of the common characteristics table are the other tables as well as entry points to their NDIS-specific routines.
A MAC driver's Interrupt Routine handles notifications from the hardware to the MAC. These notifications will cover such matters as changes in adapter status, reception of frames, and the completion of previous transmissions.
The System Request Routine handles such matters as binding (during which characteristics tables are exchanged) and unbinding. The General Request Routine handles protocol requests of the MAC. These requests include opening and closing the adapter, setting the station address, updating statistics, and many others. Both system and general requests utilize a request packet and return a completion code in a manner similar to that of an OS/2 driver's Strategy Routine.
The TransmitChain, TransferData, and ReceiveRelease routines are used during the transmission and reception of frames in order to pass data buffers between a protocol and a MAC driver.
The IndicationOff and IndicationOn routines are used to control (turn on and off) status and reception indications. Indications are notifications from a MAC driver to a protocol driver of a change in adapter status or of a reception of a frame. A protocol driver reacts to an indication in a manner similar to a MAC driver reacting to an interrupt.
Chapter 2. OS/2 Device Drivers
As mentioned in the first chapter, OS/2 device drivers contain a device driver header and a strategy routine. As these components are common to all device drivers, they will be discussed here. For more detailed information on OS/2 device drivers, see the following publications from the OS/2 2.0 Technical Library: Control Program Programming Reference (S10G-6263-0), and Physical Device Driver Reference (S10G-6266-0). In this section, we provide a summary of that information.
The Device Driver Header
The first item in the driver's initial data segment is the device driver header. This twenty-six byte data structure is organized as follows:
Offset | Size (bytes} | Description |
0x00 | 4 | Pointer to next header |
0x04 | 2 | Device Attribute Field |
0x06 | 2 | Offset to Strategy Routine |
0x08 | 2 | Offset to IDC Routine |
0x0A | 8 | Name |
0x12 | 8 | Reserved |
In order to support multiple devices within a single driver, the device driver header is a linked list. This list is terminated by a pointer of - 1 (0xFFFFFFFF), so if your driver supports only a single device, you should fill this field with -1.
The Device Attribute Field contains descriptive information used by the system. Its structure is as follows:
Bit | Description |
0 | Keyboard bit: 1 = device is the standard input device, 0 = otherwise |
1 | Screen bit: 1 = device is the standard output device, 0 = otherwise |
2 | NULL attribute bit: 1 = device is the NULL device, 0 = otherwise |
3 | Clock device bit: 1 = device is the system clock device, 0 = otherwise |
9-7 | Function Level: 001 = 0S/2 device driver (hence will be initialized in protect mode), 000 = compatibility box driver (hence will be initialized in real mode) |
11 | Open/close bit: 1 = driver requires an OPEN and CLOSE call from the system, 0 = otherwise |
12 | Shared bit: 1 = system file sharing rules apply, 0 = file ownership contentions will be resolved by the driver |
13 | IBM bit: set to zero for character devices (for block devices: 1 = supports DOS 2.0 and above file formats, 0 = supports DOS 1.0 or 1.10 formats) |
14 | Inter-driver communication (IDC) bit: 1 = driver has an IDC entry, 0 = otherwise |
15 | Device type bit: 1 = character device, 0 = block device |
The other bits are reserved, and should be set to zero.
Following the Device Attribute Field offsets into the main code segment to the entry points of the Strategy Routine and the Inter Device Communication Routine.
Character devices then have an eight byte, ASCII, blank-filled name of the device driver. This name must match the "DriverName=" keyword given in the PROTOCOL.INI file. As a device name takes precedence over a file name in a DosOpen function call, device names should contain some unusual character. A terminating "$" is traditional.
The final eight bytes of the header are reserved and should be zero filled.
The Strategy Routine
The Strategy Routine handles the system's requests of the device driver. For an OS/2 device driver, these requests include installation, normal I/O, character device-specific I/O, block device-specific I/O, and generic I/O control.
The Strategy Routine follows the far call/return mode and can be called in either real or protect mode. At entry, a pointer to a Request Packet is contained in the ES:BX register pair. This pointer is bi-modal and references the same address whether the processor is in real or in protect mode.
The Strategy Routine reads the Request Packet and takes the appropriate action. Upon completion of the request, a status field is set in the Request Packet to indicate the completion status of the request.
The Request Packet
The Request Packet consists of a thirteen byte header followed by a command specific data area. The structure of the request packet header is as follows:
Offset | Size (bytes) | Description |
0x00 | 1 | Total length of Request Packet |
0x01 | 1 | Unit code (block device) |
0x02 | 1 | Command code |
0x03 | 2 | Status field |
0x05 | 4 | Reserved |
0x09 | 4 | Queue linkage field |
The first byte gives the total length of the packet, including the header and command-specific data area. The next byte is ignored for character devices. The third byte gives the command code, indicating which function (for example, 0 = driver initialization) has been requested of the driver.
The next two bytes contain the status field. This field should be set by the driver to indicate the request completion status. Errors are indicated by setting the high order bit of this field. In this case, an error code should be returned in the low order eight bits.
The next four bytes are reserved, and the final four bytes of the header can be used to maintain a linked list of queued request packets. Either DevHlp services or the driver's own queue management may be used.
The remainder of the request packet contains command-specific data. The type and amount of command-specific data varies with each command.
The Initialization Routine
Overview
Every device driver's Strategy Routine must accept the INIT initialization request (request code = 0). The driver's code which processes this request is known as the driver's Initialization Routine. The INIT request is generated by the system during driver loading and initialization. At this time, the driver initialization thread reads the CONFIG.SYS file and interprets the "DEVICE=" command lines.
For each driver referenced, the system loads the first two segments into low memory (and any remaining segments into high memory), resolves intersegment memory references, and interprets the device driver header. Then if the device driver is a DOS-compatible driver (function level = 000) that may only run in the compatibility box, the system switches the processor to real mode, otherwise it remains in protect mode. Finally the driver initialization thread formats an INIT request packet and makes a far call to the driver's Strategy Routine to allow the driver to initialize itself.
The INIT Request Packet
The INIT request packet is twenty-three (0x17) bytes long. It consists of the standard thirteen byte header, followed by ten bytes of INIT-specific data in the following format:
Offset | Size (bytes) | Description |
0x0D | 1 | Data_1 |
0x0E | 4 | Pointer_1 |
0x12 | 4 | Pointer_2 |
0x16 | 1 | Data_2 |
On entry, Data_1 is unused. Pointer_1 contains a bi-modal pointer to the device helper (DevHlp) routine. Pointer_2 contains a far pointer to the device driver parameter string as defined in the "DEVICE=" command in the CONFIG.SYS file. This string consists of the driver file name, followed by blank-separated arguments and is null-terminated. Data_2 is set, for block drivers only, to the drive number of the next logical unit the file manager expects to install. Data_2 is unused for character drivers.
On exit, Data_1 will be set, by block drivers only, to the number of logical units supported by the device. Character drivers should set Data_1 to zero. Pointer_1 should be set to the lengths of the code and data segments after initialization time, with the high-order word giving the code segment length and the low-order word the data segment. This allows the system to free memory used only by the initialization routine. Pointer_2 will be set, by block drivers only, to a far pointer top the BIOS parameter block array. Data_2 is not used on exit.
Finally, on exit the driver should set the status field in the Request Packet header. Successful initialization is indicated by a status value of 0x0100 (only bit 8 set, indicating request done). General Failure is signaled by a status value of 0x810C (bit 15 set, indicating error, bit 8 set, indicating request done, and error code 0x0C, indicating General Failure).
OS/2 Functions Available at Initialization
There are over 200 Application Program Interface (API) function calls available under OS/2. These functions perform I/O, control processes, manage interprocess communication, and perform many other tasks. A subset of these API functions are available to a device driver at initialization time.
An OS/2 device driver's initialization routine is called at Ring 3 in protect mode, and a DOS compatibility box driver's initialization routine is called in real mode. Hence neither process management nor memory management API calls are permitted. However, at a device driver's initialization time, the system base drivers have loaded. Hence the following API calls are available at initialization time:
FileI/O: | |
Randomly reposition file pointer | |
Close a file | |
Perform generic I/O control functions | |
Open a file | |
Read from a file | |
Write to a file | |
Directory Management: | |
Delete a file | |
Terminate a pattern matching search | |
Look for a file, using pattern matching | |
Look for next file matching pattern | |
File System Information | |
Get system configuration information | |
Get current working directory | |
Get current working disk | |
Get file status | |
Get file attribute bits | |
System Message Handling | |
Retrieve message from system message file | |
Write message to system message file | |
Base-Line I/O | |
Produce system audio alert |
DevHlp Service
As device drivers run at Ring 0, kernel mode, API calls are only available during initialization time. Hence an interface to the OS/2 operating services is provided to device drivers through the DevHlp Interface. A pointer to the entry point for DevHlp calls is passed to the driver with the INIT request packet.
There are a total of fifty-seven DevHlp services. The following subsets of these are available at driver initialization time:
- System Clock Management: SchedClockAddr
- Character Que Management: QueueInit
- Memory Management: AllocGDTSelector, AllocPhys, FreePhys, Lock, PhysToGDTSelector, PhysToVirt, Unlock, UnPhysToVirt, VirtToPhys
- Interrupt Management: EOI, SetIRQ, SetROMVector, UnSetIRQ
- Timer Services: ResetTimer, SetTimer, TickCount
- System Services: GetDOSVar
- Advanced BIOS Services: ABIOSCall, ABIOSCommonEntry, FreeLIDEntry, GetLIDEntry
Chapter 3. DOS Device Drivers
There are several areas of difference between DOS and OS/2, mostly in the area of memory access and management. For real mode DOS, the driver's view of memory is straight-forward. A valid address is always valid whether operating in interrupt, system, or user context. Under OS/2 the validity of an address is entirely dependent upon its context. Extra care and planning is required to ensure that the driver's memory management strategy is correctly defined.
The Device Driver Header
The interfaces and entry points defined by NDIS are the same both for DOS and for OS/2. There are however, differences in the basic device driver structure in the two systems. These discrepancies are illustrated by the format of the driver's device header. The DOS driver's header contains two entry points referred to as Strategy and Interrupt and is eight bytes shorter than the OS/2 header. The eighteen byte DOS device header is organized as follows:
Offset | Size (bytes) | Description |
0x00 | 4 | Pointer to next header |
0x04 | 2 | Device Attribute Field |
0x06 | 2 | Offset to Strategy Routine |
0x08 | 2 | Offset to Software Interrupt Routine |
0x0A | 8 | Name |
See the section on the OS/2 device headerfor a detailed description of the Device Attribute Field.
The Strategy Routine
Under DOS when the system processes a request packet, it initially calls the driver's strategy entry point with the register pair ES:BX containing the address of the packet. The only function the DOS strategy routine performs is saving this address in local memory. Immediately after return from the driver strategy routine, DOS calls the driver at the Software Interrupt entry point. The Software Interrupt routine retrieves the pointer stored by the strategy handler and then proceeds to execute the requested task.
The Request Packet
The DOS Request Packet, like the OS/2 Request Packet, consists of a thirteen byte header followed by a command-specific data area. The structure of the request packet header is as follows:
Offset | Size (bytes) | Description |
0x00 | 1 | Total length of Request Packet |
0x01 | 1 | Unit code (block device) |
0x02 | 1 | Command code |
0x03 | 2 | Status field |
0x05 | 8 | Reserved |
See the section on the OS/2 Request Packetfor a detailed description of these fields.
The Initialization Routine
Overview
Under DOS, the Strategy Routine will save the address of the INIT request packet and return. The initialization Routine will be accessed through the Software Interrupt Entry point.
The INIT Request Packet
The DOS INIT request packet is, like the OS/2 packet, twenty-three (Ox 17) bytes long. It consists of the standard thirteen byte header, followed by ten bytes of INIT-specific data in the following format
Offset | Size (bytes) | Description |
0x0D | 1 | Data_1 |
0x0E | 4 | Pointer_1 |
0x12 | 4 | Pointer_ 2 |
0x16 | 1 | Data_ 2 |
The only difference between the DOS and OS/2 packet is in the usage of Pointer_1. On entry for a DOS device driver, Pointer_1 is unused. On exit for a DOS driver, Pointer_1 should be set to point to the first available byte of memory above the driver.
INT 21 Function Calls at Initialization Time
During system initialization, there are typically several functions which require interface with the underlying operating system. For example, the driver may wish to display a text message identifying itself, or it may wish to query the revision of the system to be sure that some piece of required functionality is present. Particularly, in the case of an NDIS driver, interaction with another driver that has already been loaded is required.
The two operating environments, DOS and OS/2, provide the means to accomplish these tasks. Under DOS, operating system functions are executed by loading parameter values into registers and executing a software interrupt. The system dispatcher fields such requests via vector X'21'. The DOS Technical Reference provides a comprehensive description of the functions available via this method.
The OS/2 driver accesses the system via far calls to API functions linked into the executable file in precisely the same manner as an application program would. This is possible because the OS/2 initialization process executes in Ring 3 just as if it were an ordinary application program.
For both DOS and for OS/2, this functionality is accessible only during system startup. Once the initialization process has returned, neither the INT 21 or the application APIs are available.
Interrupt Handlers
Hardware interrupts and the associated interrupt handlers are managed in a slightly different manner between DOS and OS/2. Please note that interrupt handler as used in this context is distinct from the Software Interrupt routine described in the preceding discussions. In the current context, the interrupt handler is the body of code that executes in response to a hardware event and not as part of system request processing.
In an OS/2 environment, the handler is called indirectly by the system's interrupt manager. At the point at which the handler begins execution, all of the system's registers have been saved and a special interrupt stack is in use. In addition, the system provides helper routines to aid in managing Process Interrupt Control (PIC) related tasks such as delivering the SetIRQ command.
Under DOS, the handler is executed directly when a hardware interrupt occurs. Preserving the processor context, switching stacks, and dismissing the interrupt through direct interaction with the PIC are tasks which the driver must perform on its own behalf.
Chapter 4. Writing a Media Access Control Driver
The Media Access Control driver bridges the gap between the physical components of the network and the logical elements contained in the protocol stack. Every network transaction is processed by the MAC driver. Great care must be taken during implementation to ensure that a highly performant and flexible interface is provided. See the NDIS Driver Developer's Tool Kit for OS/2 and DOS Programmer's Performance Guide for guidance on performance Issues.
Typical drivers contain an entry point for requests from the operating system and usually an interrupt handler as well. NDIS MAC drivers contain additional entry points to process the functions that are defined at the boundary with the protocol driver. The calling sequence for the NDIS functions differs from that used by the operating system. Normal system functions such as read, write, open, and close are passed to the driver via a parameter block. NDIS functions are executed across the boundary between the MAC and the protocol using direct calls to entry points defined by the specification. The calling sequence used is far Pascal. The calling routine pushes its parameters on the stack from left to right, and the called routine releases the stack space occupied by the parameters on exit. Return status is passed via register AX. Called routines are responsible for saving and restoring standard register variables DS, DI, SI, and BP.
The following sections of this chapter will provide detailed descriptions and code samples illustrating the process that must be implemented by a MAC driver. These samples are written in assembly language, although C could be used. These samples are examples intended to illustrate possible code structures. Where differences exist between DOS and OS/2 the code fragments contain conditionals to control the assembly time generation of a driver for one system or the other.
The Strategy and Initialization Routines
Standard operating system type functions are signaled to an OS/2 driver via a far call to the Strategy Routine entry point defined in the driver header. The argument to this call is a pointer to a parameter block containing a code that indicates the function to be executed as well as supplementary information to be used in processing the request. The only function that a MAC driver must implement is initialization. Other functions may be implemented at the developer's discretion. For example, read and write might be used to provide access to the MAC's internal structures during debug. But in all cases, whether a function is implemented or not, every request must return a completed status in order to prevent exhaustion of system resources.
The initialization function is signaled to the driver during the processing of the CONFIG.SYS file at system startup time. During initialization, the driver establishes its operating environment, locates its adapter, and allocates the resources necessary for operation.
The PROTOCOL.INI file contains the definition of the communications subsystem that will be built. The PROTOCOL.INI file contains an entry for each driver that is configured in the NDIS environment. As part of its initialization path, the Protocol Manager reads this file and parses its contents into a tree structure. Each node directly below the root of the tree describes a [module] section from this definitions file.
Opening the Protocol Manager
As each NDIS driver initializes, it interacts with the Protocol Manager to obtain its individual parameters and to register itself. Access to the Protocol Manager is via the file system APIs. This is possible because during startup, the driver initialization code executes in Ring 3, just as if it were a normal application. The first step required is to open the Protocol Manager. The format of the function should be similar to that given below.
; ;-- Get handle for Protocol Manager ; if OS2 push ds ; Far pointer to name (input) push offset ProtocolManagerName push ds ; Far pointer to handle (output) push offset ProtocolManagerHandle push ds ; Far pointer (output) push offset ActionTaken push 0 ; Dword file size (output) push 0 push 1 ; Flag (input) push 0C2h ; Mode (input) push 0 ; Dword reserved push 0 call DOSOPEN or ax, ax ; Return status? jnz NoManager ; Display error and abort else ; DOS interface mov dx, offset ProtocolManagerName mov ax, 3d00h ; DOS open function int 21h jc NoManager endif
Protocol Manager Requests
After the Protocol Manager open has succeeded and the file handle is obtained, requests are executed using IOCTL functions, passing a pointer to a parameter block which defines the function to be performed. Under OS/2 the generic IOCTL, function code 16, is used to provide access to all of the functionality provided by the Protocol Manager. The Category code used is 0x81 signifying LAN Manager, with a function code of 0x58, indicating Protocol Manager type command. The parameter buffer contains a far pointer to a common request block structure. The structure given below describes the Protocol Manager request block.
PMBlock struc ; Function code PMCode dw ? ; Status returned by PMStatus dw ? ; ProtMan PMPtrl dd ? ; First parameter PMPtr2 dd ? ; Second parameter PMWord dw ? ; Third parameter PMBlock ends
Getting Configuration Information
Typically, the next step is to gain access to the ConfigMemoryImage parsed from PROTOCOL.INI by the Protocol Manager. The code fragment provided below illustrates the correct procedure for filling in the request block and invoking the Protocol Manager.
; ;-- Fill in request block. Only parameter required ; is function code. ; mov PMReqBlk.PMCode, GetProtManInfo if OS2 push 0 ; Far null pointer push 0 push ds ; Far pointer to ReqBlk push offset PMReqBlk push ProtManCode ; 0x58 push LanManCat ; 0x81 mov ax,[ProtoclManagerHandle] push ax ; Handle returned by open call DOSDEVIOCTL ; System API or ax, ax ; Return okay? jnz NoConfigInfo ; Display error and abort else ; DOS mov bx, [ProtocolManagerHandle] mov dx, offset PMReqBlk mov cx, 14 ; size of block mov ax, 4402h ; IOCTL function int 21h jc NoConfigInfo endif ; ;-- Success. First pointer contains address of ; ConfigMemoryInfo structure. Word parameter ; contains revision of Protocol Manager. Check ; for acceptable values. ; mov ax, PMReqBlk.PMWord cmp ax, ProtManLevel jne InvalidProtMan ;Display error and abort lds si,PMReqBlk.PMPtrl ;Get pointer to config tree
The driver must now traverse the list of ModuleConfig structures, seeking the one that contains its operational parameters. Note that although the nodes are based an the square-bracketed [ModuleName] sections contained in the PROTOCOL.INI file, ModuleName is not the correct key to be used for the search. The value of this field is user definable and may be installation specific. The search should be based on the "DriverName=" keyword. This entry is required within every ModuleName section and must accurately reflect the name used within the driver's device header. Other fields are optional in general, but may be required by specific drivers. Below is an example PROTOCOL.INI entry for the driver for the fictional BITHOSE card. This driver requires two additional parameters, namely the I/O base address of the card and the IRQ to be used.
[bithose_NIF] DriverName = bithose$ Base = 0x300 IntLevel = 3
When the Protocol Manager builds the ConfigMemoryImage, lower case characters are converted to upper case and white space and comment lines are ignored. During initialization, the bithose driver searches for a ModuleName section with the correct DriverName value.
;-- The following structure definitions are used ; by the parsing routine below. ; ModuleConfig struc ModuleNext dd 0 ; Next in chain or ; Null ModulePrev dd 0 ; Previous in chain ModuleName db 16 dup (0) ; Square bracket name KeyWordList dd 0 ; First keyword ModuleConfig ends KeyWord struc KeyWordNext dd 0 ; Next in chain or ; NULL KeyWordPrev dd 0 ; Previous in chain KeyWordName db 16 dup (0) ; Keyword text NumParams dw 0 ; Count of parameters ; ;-- The next section repeats NumParams times ; ParamType dw 0 ; Type of parameter ; =0 then long ; =1 then ASCIIZ string ParamValue dd 0 ; Variable depending ; on type Keyword ends ; ;-- Find our ModuleName section. ; ds:si--> Head of ModuleConfig linked list. ; CheckEndModules: mov ax, ds ; Check for end of or ax, si ; the line jz NoDriverName ; Display error and ; abort ; push ds ; Save our place push si lds si, [si].KeyWordList ; CheckEndKeywords: mov ax, ds or ax, si ; Null pointer? jz EndKeywords ; Yes - try next module ; mov bx, si ; Save structure pointer mov si, [si].KeyWordName mov di, offset DriverKeyword mov cx, 10 ; Length of "DRIVERNAME" cld rep cmpsb jcxz FoundDriverKeyword ; NextKeyword: lds si, [bx].NextKeyword jmp CheckEndKeyWords ; FoundDriverKeyword: cmp [bx].NumParams, 1 jne NextKeyword ; Invalid entry lea si, [bx].Param cmp [si].ParamType, ASCIIZ jne NextKeyword mov cx, OurNameLen cmp cx, [si].ParamLen jne NextKeyWord lea si, [si].ParamValue mov di, offset OurName rep cmpsb jcxz FoundOurName jmp NextKeyword ; EndKeywords: pop si pop ds ; Restore ; ModuleConfig ptr lds si, [si].NextModule jmp CheckEndModules ; FoundOurName: pop si pop ds ; We have our section ; now
Building the Characteristics Tables
After locating the correct ModuleName section, the driver should copy the Name specified by the user into its common characteristics table. The driver should scan the keywords linked to this module for any specific required parameters. In this example, the bithose driver would continue the scan for the two additional required parameters. If they are not present, the driver may choose to display an error message and abort its initialization. For each parameter encountered, the driver should check to ensure that the parameter is of the correct type and that the value given is within range.
After parsing its ModuleConfig section, the driver should have enough information to query its adapter and complete the initialization of its characteristics tables. NDIS defines a set of tables that are maintained by conformant drivers. These tables contain information describing the capabilities of the driver and adapter, as well as several entry points within the driver that are callable by external entities across the NDIS boundary. Most of the fields in the table may be initialized when the driver is coded, with the default values in selected fields overridden by information gained from PROTOCOL.INI parsing.
Several fields within these tables contain far pointers to be used by the protocol driver after binding. The values contained must be Ring 0 GDT selectors. They can not be established at initialization time because the driver is operating in Ring 3. The value for these pointer fields are properly established using the SEG assembler pseudo-op as illustrated in the example below, describing the NDIS System Request dispatch entry point as it might appear within the MAC's Common Characteristics Table.
dw offset System dw SEG System
Completing Initialization
After the Characteristics Tables have been completely built, the MAC driver can proceed to the final stages of initialization. Depending on the MAC, this may, under OS/2 require reserving GDT selectors and locking extra segments for use during operation. When the implementation-specific initialization functions have completed, the driver is ready to complete its start-up path by registering with the Protocol Manager. This function is executed as a generic IOCTL as described in the preceding section on obtaining the ConfigMemoryInfo. The format of the call is described below.
; ;-- Fill in request block. Required parameters are ; function code and far pointer to the Common ; Characteristics Table. Pointer 2 (bindings ; list) must be null for MAC's. ; mov PMReqBlk.PMCode, RegisterModule mov word ptr PMReqBlk.PMPtrl, offset CCTable mov word ptr PMReqBlk.PMPtrl + 2, SEG CCTable mov word ptr PMReqBlk.PMPtr2, 0 mov word ptr PMReqBlk.PMPtr2 + 2, 0 ; if OS2 push 0 ; Far null pointer push 0 push ds ; Far pointer to ReqBlk push offset PMReqBlk push ProtManCode ; 0x58 push LanManCat ; 0x81 mov ax, [ProtoclManagerHandle] push ax ; Handle returned by open call DOSDEVIOCTL ; System API or ax, ax ; Return okay? jnz RegisterFail ; Display error and abort else ; DOS mov bx, [ProtocolManagerHandle] mov dx, offset PMReqblk mov cx, 14 mov ax, 4402h ; DOS IOCTL int 21h jc RegisterFail endif
Initialization is now completed and no further interaction with the Protocol Manager is required. The file handle used for the interface may now be closed and the driver may exit back to the OS/2 configuration processor.
The System Request Routine
At some point after the system has completed boot up, an application program may request that the network interface be started. This is signaled to the Protocol Manager via a BindAndStart function. A typical source of this request is the NETBIND.EXE program. During the RegisterModule phase, the Protocol Manager built a binding tree describing the protocol driver to MAC linkages to be established in order to create the communications subsystem. Upon receipt of the BindAndStart command the Protocol Manager traverses this tree, requesting that the higher level entities (protocol drivers) bind to the lower (MAC drivers).
For the MAC driver, the end result of this activity will, if the system is correctly configured, generate one and only one bind request from an upper level routine. This request may be issued by a single protocol driver module or it may be issued by a sub-function of the Protocol Manager called VECTOR acting on behalf of multiple protocol driver modules that have specified a binding to the MAC driver. In either case, the interface to the MAC driver is identical. When the MAC is invoked, the stack contains the parameters passed by the protocol driver in the following format
stack --> dword far return --> word MAC's data_seg --> word opcode for Bind (2) --> word pad (0) --> dword pointer where to return CCTable address --> dword callers CCTable address
The Bind System Request
Bind is the only System Request that MAC drivers implement. The MAC should be prepared to bind with no more than one upper lead module. Succeeding Bind requests should return an invalid status. The code fragment provided below demonstrates the Bind procedure.
System proc far push bp ; Save frame pointer mov bp, sp ; And establish ; addressability push ds ; Save push di push si mov ds, [bp].SysDs ; Our data_seg mov ax, INVALID_FUNCTION cmp [bp].SysFunc, BIND jne SysExit ; Nothing else mov ax, [BindStatus] or ax, ax ; We update this when a ; bind has occurred. ; If 1=0 then ; already bound. jnz SysExit ; ;-- Take control of the adapter now. It shouldn't be ; done during bootup in case the adapter is being ; used for remote boot. ; call GetAdapter ; Do adapter specific stuff or ax, ax ; Make sure all went well jnz SysExit ; Some kind of hardware ; problem - fail the bind ; ;-- Mark ourselves as bound and copy in some of the ; Protocol's information for fast access. ; mov [BindStatus], INVALID_FUNCTION or SpecStatusTable.SpecStatus, MACBound mov ax, ds mov es, ax mov di, offset ProtocolTable lds si, [bp].SysProtTable mov ax, [si].CCTableDS ; Save Protocol's DS mov es: [ProtcolDS], ax lds si, [si].CCTableLowerDispatch mov cx, SizeLowerDispatch cld rep movsb xor ax, ax ; Status cleared SysExit: pop si pop di pop ds pop bp ret SizeSysParms ; Clean up stack and exit System endp
If the MAC driver has chosen not to implement Open and Close then, on exit from the System Request function after a successful Bind, the adapter and the MAC should be fully conditioned and ready to support network traffic.
The Indication Routines
An indication, as generated by the MAC to the protocol driver, is a higher level notification of an adapter-generated event. Indications may occur when a frame is received, when an adapter error condition occurs, or, if supported by the underlying hardware. as the result of an InterruptRequest Gall Request issued at some earlier point in time by the protocol driver MAC drivers implement two entry points, IndicationOn and IndicationOff, that provide the protocol driver with a logical mechanism for enabling and disabling these events.
The MAC driver maintains its indication level as a counter. IndicationOff increments the counter and IndicationOn decrements it. At any point if the value of the counter is non-zero, indications may not be signaled to the protocol drive. This correctly handles unwinding from the case where IndicationOff requests have been nested.
On entry to the indication routines, the stack holds the calling context as follows:
Stack --> dword far return --> word MAC's data_seg
IndicationOff
The code fragment below provides an example IndicationOff routine. As part of its process path, the routine calls an adapter specific routine to disable its interrupt generation. Depending on the hardware, it may be possible to execute a partial disable, allowing the driver to continue processing non-indication generating functions such as TransmitChain.
IndicationOff proc far push bp ; Standard preamble mov bp, sp push ds push di push si mov ax, [bp].IndDS ; cli ; Per NDIS we return disabled mov al, [IndicationLevel] inc [IndicationLevel] or al, al ; Enabled before? jnz IOffExit ; Yes - HW already disabled ; call AdapterDisable ; Specific to adapter ; IOffExit xor ax, ax ; Return okay pop si pop di pop ds pop bp ret IndParmSize IndicationOff endp
IndicationOn
The IndicationOn procedure is the complement of the IndicationOff function. The MACs indication level is decremented and, if the count reaches zero, adapter interrupts are re-enabled.
IndicationOn proc far push bp ; Standard preamble mov bp, sp ; Get stack addressability push ds push di push si mov ds, [bp].IndDS ; Our data_seg ; cli ; Per NDIS we return disabled dec [IndicationLevel] jnz IOnExit ; Still off ; call AdapterEnable ; HW specific to restart ; Must run disabled because ; indications not allowed within ; the context of this call ; IOnExit xor ax, ax ; Status = okay pop si pop di pop ds pop bp ret IndParmSize IndicationOn endp
In addition to these two routines, the indication level is implicitly manipulated by the MAC driver whenever an indication is about to be signaled to the protocol drive. This will be described more fully in the following sections describing the specific indications.
The TransmitChain Routine
The MAC's TransmitChain entry point is called by the protocol driver when there is a frame ready to be dispatched to the network. MAC's may implement TransmitChain synchronously or asynchronously. If the transmission is completed successfully within the context of this call, a successful return status is provided to the calling protocol. If the adapter is currently unable to accept another frame for transmission, the MAC may queue the request and return immediately to the protocol with a status indicating that the request was pended. At some later point when adapter resources become available, probably within the context of the interrupt handler, the frame can be dequeued and transmitted.
If transmission is deferred, the MAC has two additional responsibilities. First, the TransmitChainBuffer Descriptor and any immediate data it describes are valid only during the execution of the original TransmitChain call. Therefore, these volatile portions of the frame description must be copied into the MAC's memory space before returning. Second, when the deferred frame is finally transmitted, it must be confirmed to the protocol driver via the TransmitConfirm function described below.
On entry to TransmitChain, the stack contains the arguments provided by the protocol driver to be used in processing this request.
stack --> dword far return --> word MAC's data_seg --> dword pointer to buffer descriptor --> word request handle --> word Protocol ID
TransmitChain proc far push bp ; Standard preamble mov bp, sp push ds push es push di push si ; ;-- First check if we can start a transmit now. ; call CheckResources ; Adapter specific or ax, ax ; ax=0 then all systems go jz TxOkay ; ;-- Else we have to queue request. ; call CopyChain ; Copy descriptor, immediate ; data, handle, and protocol ID ; ss:bp -->TxChain info mov ax, REQUEST_QUEUED jmp TxChainExit ; Return - xmit deferred ; ;-- We can send now. ; Call DoTransmit ; Adapter specific ; ss:bp-->Txchain info ; Returns status of xmit. ; TxChainExit: pop si pop di pop es pop ds pop bp ret TxChainParmSize TransmitChain endp
The Interrupt Routine
In large part, the design of the interrupt routine is dictated by the functionality of the adapter. There are, however, certain common sense guidelines to which all drivers should adhere.
The Interrupt Routine should be divided into two major sections. The front end is responsible for time-critical functions that execute during initial processing with the adapter disabled. The back end, while still in interrupt context, handles the less critical tasks after the adapter has been reconditioned to process network traffic. It is recommended that nesting within the Interrupt Routine be kept to a minimum. One invocation of the Interrupt Routine can completely clear the adapter's interrupt queue, efficiently using system resources. If multiple invocations of the Interrupt Routine are allowed to occur, then the potential exists to exhaust finite system resources such as stack space.
A simple, workable methodology, that eliminates Interrupt Routine nesting, gates access to the two portions of the Interrupt Routine based on memory resident flags. On entry the front end Interrupt Routine dismisses the interrupt at the PIC and, while interrupts are disabled, the following code sequence guarantees exclusive access to the Interrupt Routine code. A similar mechanism can be used when the front end handler has completed his critical execution path and is ready to continue the back end processing if necessary.
; ;-- Get and set the exclusion flag. ; mov ax, 1 xchg al, [Level1Flag] or al, al jnz IntlExit ; Already running - bail out ;-- Execute front end code ; - - - ; ;-- Front end completed. Clear semaphore and see ; if tail is running. ; cli ; Tests must execute disabled xor al, al xchg [Level1Flag], al ; Get/Clear level 1 xchg [Level2Flag], al ; Get/Set level 2 or al, al jz ExecLevel2 ; Not running - go execute ; IntlExit: if DOS ; Restore registers and swap ; back to original stack popa pop es pop ds mov ss, cs: [savedss] mov sp, cs: [savedsp] iret else ; OS/2 ret endif ; ;-- Execute back end code. ; ExecLevel2: if DOS ; Swap off of interrupt stack popa pop es pop ds mov ss, cs: [savedss] mov sp, cs: [savedsp] end - - - cli ; Clear until we exit mov [Level2Flag], 0 if DOS iret else ; OS/2 ret
With this technique, at most one iteration of the front end handler and one iteration of the back end handler we be active at any one time
Time-Critical Tasks
On entry to the Interrupt Routine, there are several house-keeping functions that are required for all drivers. When the Interrupt Routine begins execution, interrupts are disabled. Several critical tasks must be performed before re-enabling. The adapter's interrupt should be masked, either at the PIC or at the adapter itself, whichever is more convenient, and an End-of-Interrupt command must be delivered to the PIC to re-enable normal hardware interrupt processing. If running under DOS, the driver must swap to a private interrupt stack. Finally, with the Interrupt Routine secure from recursion, the processor interrupt flag should be set to allow normal system operation.
Changing Mode
Before continuing further along its processing path, the driver must ensure that it is executing in protected mode. This is a requirement if any upcalls to the protocol are to be executed during interrupt handling. The procedure for ascertaining whether or not the Interrupt Routine is running in protected mode and, if necessary, executing the mode switch is given below.
if OS2 smsw ax ; Get machine status word mov [ModeSwitch], ax shr ax, 1 ; Shift out Protected Mode bit jc InProtMode ; Okay ; mov dl, RealtoProt ; 0x2F call dword ptr [DevHelp] mov [ModeSwitch], 1 ; InProtMode: endif
Similarly, during the Interrupt Routine's exit procedure, the processor must be resumed to real mode if a switch has been executed at the driver's request.
; ;-- Ready to exit. See if we did mode switch. ; if OS2 xor al, al xchg [ModeSwitch], al or al, al ; =0 then no switch jz NoSwitch ; mov dl, ProttoReal ; 0x30 call dword ptr [DevHelp] ; NoSwitch: endif
Receiving Frames
There are two basic mechanisms provided for passing received frames up to the protocol. The choice is based primarily on the type of interface supported by the adapter. For adapters that support shared memory such that the MAC drive has complete visibility to the entire received frame, the ReceiveChain primitive provides the more efficient mechanism for conveying frames to the protocol driver. If, on the other hand, the adapter interfaces via programmed I/O, ReceiveLookahead offers a facility whereby the driver can input a relatively small leading portion of the received frame and advertise it to the protocol driver. Drivers that generally use ReceiveChain may occasionally revert to ReceiveLookahead in situations where adapter memory resources are running low. Both methods are described in more detail below.
ReceiveLookahead and ReceiveChain are both defined as indications, and may be suppressed based on the value of the indication level variable. The level of indication may be manipulated explicitly by the protocol driver via the IndicationOn and IndicationOff MAC entries. Additionally, the MAC explicitly disables indications before calling the protocol driver at an indication entry point. This ensures that the protocol driver will not be interrupted during indication processing by the arrival of another indication. Beside the other arguments passed to the protocol driver during an indication call, the MAC passes the address of a byte location called the IndicateFlag. Before the upcall, the MAC initializes this location with the value 0xFF. During indication processing the protocol driver may clear this location. On return, the MAC examines the value contained in the flag. If it has been cleared, then indications remain disabled. Otherwise, the MAC decrements the value of indication level potentially re-enabling indications.
ReceiveLookahead
The code fragment given below illustrates the sequence required to signal a ReceiveLookahead indication to the protocol driver. If the Protocol accepts the frame, it will call the MAC driver's TransferData entry within the context of the ReceiveLookahead call in order to receive a copy of the frame data.
; ;-- Execute a ReceiveLookahead upcall. The assumption is ; that if we have reached this point indications are ; currently enabled. ; mov byte ptr [IndicateFlag], -1 inc byte ptr [IndicationLevel1] push [MacId] ; Assigned by ProtMan push [FrameSize] ; Total size of frame push [LookAheadLen] ; Range of LookAhead ; This could be entire frame push ds ; Far ptr to LookAhead buffer push offset LookAheadBuff push ds ; Far ptr to action flag push offset IndicateFlag push [ProtocolDS] ; Obtained during bind push dword ptr [ReceiveLookahead] ; Address copied during bind ; ;-- If the Protocol wants the frame it will call our ; TransferData entry from within the context of this call ; mov dl [IndicateFlag] ; On return either 0 or -1 add [IndicationLevel, dl inc [NeedIndComplete] ; Remember we need a complete
ReceiveChain
The process path for ReceiveChain is conceptually similar to that used by ReceiveLookahead. ReceiveChain is more appropriately used when the entire frame is available in memory visible to the MAC driver. The indication level is managed similarly for both calls. With ReceiveChain the protocol driver may elect to copy the frame immediately into its space or it may defer the copy and queue the frame for copy and process during back end interrupt processing. If the protocol driver chooses to defer, the MAC driver must maintain the data buffers until they are explicitly released.
; ;-- ReceiveChain upcall processing. On entry the ; frame buffers have already been linked to the ; BufDescr. ; mov byte ptr [IndicateFlag], -1 inc byte ptr [IndicationLevel] inc word ptr [RequestHandle] ; Generate a new handle push push [MacId] ; Assigned by ProtMan push [FrameSize] ; Total size of frame push [RequestHandle] ; Identify this request push ds ; Far ptr to BufDescr push offset RxBufDescr ; These are volatile so we ; we only need one push ds ; Far ptr to action flag push offset IndicateFlag push [ProtocolDS] ; Obtained during bind call dword ptr [ReceiveChain] ; Address copied ; during bind mov dl, [IndicateFlag] ; On return either 0 or -1 add [IndicationLevel], dl inc [NeedIndComplete] ; Remember that we need a ; complete cmp ax, REQUEST_QUEUED ; If no -- jne ReleaseBuf ; then we can release call QueuedRecv ; Put buffers on a waiting ; queue. The unique handle ; generated before the ; call will be used for ID ; during release
Note that a MAC that normally uses ReceiveChain may switch temporarily to ReceiveLookahead if the protocol driver has deferred processing on several frames and the MAC is running low on resources. ReceiveLookahead forces the protocol driver to process or reject the frame synchronously within the context of the call.
Other Tasks
In addition to receive processing, there are several other tasks that the interrupt Interrupt Routine may be called upon to manage. Adapter errors should be monitored and if necessary AdapterCheck status indications may be generated to the protocol driver in response to serious failures. If a transmit completion occurs, the MAC must generate a confirmation to the protocol driver, using the request handle passed with the original TransmitChain. If another frame is queued, a new transmit request can be passed to the adapter.
Only those functions that are time critical should be processed during front end interrupt handling. Whenever possible, work should be deferred until post processing when the adapter is re-enabled. Before exiting its back end interrupt processing, the MAC driver should generate an IndicationComplete upcall to allow the protocol driver to complete any of the processing it has deferred during indication time.
The TransferData Routine
TransferData is used only in conjunction with ReceiveLookahead. It describes a service entry point within the MAC driver that the protocol driver may invoke in order to transfer a received frame into its space. This call is valid only within the context of a ReceiveLookahead upcall from the MAC.
The MAC driver processes the data from the network card into the buffers linked to the TransferData buffer descriptor. The actual method of interface, DMA, programmed I/O, etc., is specific to the adapter. The process completes until either the entire frame has been transferred or until the protocol driver's buffers have been completely filled. In either case, the actual number of bytes copied is returned to the protocol driver in the location pointed to by the BytesCopied argument.
Depending on the hardware, the MAC may be able to support multiple calls to TransferData within the context of a single ReceiveLookahead upcall. If at all possible, the MAC should support this feature to allow for the case where multiple protocols are bound, via Vector, to a single MAC.
The ReceiveRelease Routine
ReceiveRelease is a MAC entry point called by the protocol driver when a ReceiveChain indication has been deferred. The protocol driver must remember the handle passed with the original ReceiveChain upcall and pass it back to the MAC. The handle is used to uniquely identify the buffers that are to be released.
The General Request Routines
The General Requests provide the protocol driver with the ability to perform adapter administration operations. All of the requests are handled via a single entry point. Specific operations are demultiplexed by the MAC via a function code parameter.
The MAC may choose to either handle the requests synchronously or to queue the request for later processing. If the request is deferred, the MAC must remember the handle and protocol ID passed with the call to be used later when the request is confirmed.
Notices
January, 1996
Issued by:
IBM Corporation
Personal Software Products
11400 Burnet Road
Austin, Texas 78758
Second Edition (January 1996)
First Edition (May 1993)
The following paragraph does not apply to the United Kingdom or any country where such provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this statement may not apply to you.
This publication could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; these changes will be incorporated in new editions of the publication. IBM may make improvements and/or changes in the product(s) and/or program(s) described in this publication at any time.
It is possible that this publication may contain reference to, or information about, IBM products (machines and programs), programming, or services that are not announced in your country. Such references or information must not be construed to mean that IBM intends to announce such IBM products, programming, or services in your country.
Copyright Notices
© Copyright International Business Machines Corporation 1993. All rights reserved.
Note to U.S. Government Users - Documentation related to restricted rights - Use, duplication or disclosure is subject to restrictions set forth in GSA ADP Schedule Contract with IBM Corp.
Disclaimers
References in this products to IBM products, programs or services do not imply that IBM intends to make these available in all countries in which IBM operates. Any reference to an IBM product, program or service is not intended to state or imply that only IBM's product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any of the intellectual property rights of IBM may be used instead of the IBM product, program, or service. The evaluation and verification of operation in conjunction with other products except those expressly designated by IBM, are the responsibility of the user.
IBM may have patents or pending patent applications covering subject matter this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries in writing to the IBM Director of Commercial relations IBM Corporation Purchase NY 10577 - USA.
Trademarks
The following terms are trademarks of the International Business Machine Company:
IBM OS/2
The following terms are trademarks of the indicated companies:
Microsoft Microsoft Corporation
LAN Manager Microsoft Corporation
3Com 3Com Corporation
Table of Contents
- Introduction
- Performance Criteria
- Performance Issues in NDIS MAC Device Driver Design
- Performance Important NDIS Verbs
- Interrupt Processing
- OS/2 System Service Usage
- Programming Practices
- Notices
[[[#PerformanceCriteria|next]]][[[#toc|parent]]][[[#toc|TOC]]]
Introduction
A Network Driver Interface Specification (NDIS) Media Access Control (MAC) device driver provides the software interface with a Specific communication adapter and makes that communication adapter system resources available to communications protocol stacks through the NDIS programming interface.
This document provides guidance to the creators of NDIS MAC device drivers to help them achieve good performance from their device driver implementations.
The performance that is important to focus on for an NDIS MAC device driver is the performance that the communications users see. Communications users are most sensitive to the time it takes to send their data across the communications network. From the performance point of view this suggests that we focus on making the data flow paths as fast as possible for any quantity of data. Accomplishing fast data transfer requires analysis of three areas:
- fast data flow between the device driver and the protocol stack
- fast data flow through the device driver
- fast data flow between the device driver and the adapter card.
In addition to minimizing the latency of the data flow paths, minimizing the CPU utilization of the NDIS MAC device driver is also important. Optimizing CPU utilization is necessary in servers, since the performance of the server is often a bottleneck in client-server transactions.
The performance of the NDIS MAC device driver itself is important as well as how it interfaces with the rest of the hardware and software system.
This document:
- explains the key measures used in evaluating NDIS MAC device driver performance
- discusses overall design considerations
- identifies NDIS verbs of particular performance importance
- discusses interrupt processing
- discusses OS/2 system usage
- discusses programming practices.
This information may help NDIS MAC device driver creators understand the performance effects of the many choices available to them and result in better performing NDIS MAC device drivers.
Performance Criteria
Performance for a NDIS MAC device driver is evaluated by three quantities: latency, throughput and system processor utilization. Latency is a measure of how fast the transport can put data on, or get data off, the communication medium. Latency can be broken down into transmit latency and receive latency. Latency is often measured by the time used to send and receive a few bytes of data. Smaller latency is better.
Throughput is a measure of how well data can be kept flowing on to or off of the communication medium. Throughput is measured in units of work per unit time. The amount of data used in throughput evaluation is large so that the effects of data handling and buffer management are apparent. For communications applications, throughput is often measured in units of bytes per second, or units of frames per second (for a range of frame sizes). Larger throughput is better.
Finally, system processor utilization shows how much of the system processor is used for flowing data in a throughput environment. Smaller system processor utilization is better.
End users are interested in the performance of the entire communications stack. It is important to run the device driver with different protocol stacks and see how each protocol stack uses the device driver. We recommend using the IBM NetBIOS and IBM 802.2 protocol stacks.
In order to focus on NDIS MAC device driver performance independently of other communication media traffic, performance measurements should be made on an isolated communication network.
Good system performance is the real end goal. NDIS MAC device driver performance is one component of communication system performance. System needs or bottlenecks may suggest the best tuning for communication system components to achieve the best system performance. For example a system that depends on fast communication is likely to need the best latency and throughput. However a system that has big CPU demands and little communication may run best when communication system parameters are tuned for least CPU utilization. NDIS MAC device drivers need to perform well across the spectrum of communication system tuning.
Performance Issues In NDIS MAC Device Driver Design
The performance of an NDIS MAC device driver is a key determinant in communications performance and is often a major factor in overall system performance. Consequently, considerable effort should be expended to ensure that each NDIS MAC device driver is high performing. In this section, we discuss overall design issues which affect the performance of an NDIS MAC device driver.
First, though, one must keep in mind that the recommendations in this document are general in nature. Each of the recommendations in this document has been implemented in an NDIS MAC device driver and has been shown to improve its performance. However, the specifics of the adapter play a large role in determining how effective these suggestions will be in improving performance. These specifics include the communications medium to which the adapter interfaces, the hardware design of the adapter, and the software interface specification by which the MAC device driver talks to the adapter. How much each contributing factor affects performance varies from adapter to adapter. The key point is that it is crucial to understand in detail the adapter's design and specifications.
The first NDIS MAC device driver design issue is related to multiple adapter support. If multiple adapters which use the same MAC driver can be present in a single machine, then there are two basic design choices:
- up a single device driver model
- use the multiple device driver model i.e., load a copy of the device driver for each adapter.
The single device driver model is strongly recommended for best performance. It avoids two key drawbacks of the multiple driver model: one, the extra RAM used by multiple instantiations of the code segment; and, two, the need for process and/or context switches to change from servicing one adapter to servicing a different adapter. Using the single device driver model, there would be one code segment operating on multiple data segments, one for each adapter. To move from servicing one adapter to servicing another now requires only a segment register load. Segment register loads are considerably less expensive than (operating system dependent) context switches. Note also that in the default case of a single adapter in a machine, the single device driver model will be the same as the multiple device driver model.
If one adopts the single device driver model, then that device driver is responsible for ensuring that service to each adapter is fair. Fairness is provided by selecting the first adapter to check for a pending interrupt in a round robin order. After that, all work is done for each adapter before proceeding to the next adapter. This ensures that the processing will be interwoven for all adapters. When the device driver is entered, all interrupts for all adapters handled by that device driver should be masked. We note that fairness must be ensured both when multiple adapters present interrupts at the same time and when the processing for one adapter is completed before deciding whether or not to return control to the operating system. In particular, before returning control to the operating system, all adapters should be checked for additional work.
After fairness of service among adapters is ensured, two issues of fairness in the processing of work for a single adapter must be addressed. The first fairness issue relates to how the MAC driver learns of adapter events which require service. Either the adapter will notify the MAC driver via interrupt or the MAC driver will find out by checking the adapter's status. This issue will be revisited in the Interrupt Processing section. The basic idea is that once the interrupt handler is in control through an interrupt driven event, further interrupts from the adapter should be masked until all worked discoverable by checking adapter status has been completed. Each particular NDIS MAC device driver must decide for itself how to balance its own interrupt driven and adapter status checking natures.
The second fairness issue deals with the balance of processing between transmit and receive work. The balance that the device driver must strive to maintain is between keeping the adapter as busy as possible with data to be transmitted and keeping the protocol as busy as possible processing data that has been received.
This balance depends on whether the software interface to the adapter is via shared RAM or via direct memory access (DMA). For adapters which use DMA, the corresponding NDIS MAC device driver may have to allocate its own receive buffers into which the adapter will DMA received data. These buffers will become critical resources and may turn into performance bottlenecks if not handled properly.
Two key adapter events to which the MAC driver must give priority are the processing of receive frames and the completion of previously transmitted frames. Processing receive frames quickly improves protocol responsiveness and frees receive buffers for the next incoming frame. Early detection of the completion of previously transmitted frames keeps the adapter busy transmitting additional frames. This happens because the MAC driver can pass additional data to the adapter once it determines that a previous transmit request has been fulfilled. MAC driver handling of these two key events is dependent upon the software interface to the adapter.
The design of NDIS lends itself particularly well to the use of scatter lists on the receive path and gather lists on the transmit path. If the adapter supports such lists, then the high performing NDIS MAC device driver must take advantage of them. Doing so will eliminate the need to copy segmented, and possibly physically dispersed, frames into separate, contiguous, MAC allocated buffer space. The performance gains using this approach are clear:
- fewer data copies and, hence, reduced CPU utilization
- smaller data segments
- less data buffer manipulation.
Finally, each procedure in an NDIS MAC device driver should be coded as efficiently as possible. Efficient coding translates directly into improved performance by reducing CPU usage. In addition, the device driver should take advantage of any special adapter capabilities which could optimize performance. An example of such a capability would be an adapter that allows the device driver to begin handling the start of received data before the entire transmission is received.
The next two sections, Performance Important NDIS Verbs and Interrupt Processing, describe two areas where special attention must be focused to produce a high performing driver. The sections System Service Usage and Programming Practices provide suggestions which should be followed throughout in the implementation of an NDIS MAC device driver.
Performance Important NDIS Verbs
An NDIS MAC device driver is responsible for supporting a large number of NDIS primitives. However, only those primitives in the 'Direct Primitives' class directly affect critical path transmit and receive performance. Primitives in the other three classes: 'General Requests', 'System Requests', and 'Protocol Manager Primitives' do not usually occur on performance critical paths. While developers should strive to implement each piece of code efficiently, special attention must be paid in coding 'Direct Primitives'.
The primitives which most affect critical path transmit and receive performance are part of the protocol to MAC interface described in Chapter 3 of the NDIS Specification. These primitives are:
- Transmit Chain
- TransferData
and, to a lesser extent, the remaining 'Direct Primitives':
- TransmitConfirm
- ReceiveRelease
- ReceiveLookAhead
- ReceiveChain
- IndicationOn
- IndicationOff
- IndicationComplete
For DOS NDIS MAC device drivers, the InterruptRequest primitive must be supported, else the performance of protocol drivers (including the DOS LAN Support Program) will be severely degraded.
The two methods of handling received data merit some discussion. ReceiveChain should be used if all the data received is system addressable when the MAC device driver gets the interrupt. ReceiveLookAhead should be used if either of two conditions hold. First, ReceiveLookAhead should be used if not all of the data is system addressable when the MAC device driver is interrupted. In this case, the data will need to be copied and this is a situation ReceiveLookAhead and the associated TransferData handle well. Second, ReceiveLookAhead should be used if not all the data has been received by the adapter when the interrupt is raised. In this case, protocol drivers may inspect and process the head of the frame without waiting for the entire frame to be received.
MAC driver processing in support of the MAC to adapter interface is also crucial for best critical path performance and will be discussed in the next section, Interrupt Processing. Since much of the processing of direct primitives involves interrupt processing, these two sections are necessarily interrelated.
TransmitChain
TransmitChain is the NDIS primitive used by protocols to transmit data. The protocol passes a transmit buffer descriptor consisting of a pointer to up to 64 bytes of immediate data and a list of data blocks. Each data block contains a pointer to up to 64 kilobytes of data. The key to a high performing implementation of TransmitChain is to pass the data to the adapter as quickly as possible. The actual details will vary with the adapter's software interface, but certain ideas are common to all adapters. The key idea is to eliminate any activities on this critical path which could be done in advance, either in initialization or during other non-critical path processing. Hence, any device driver data areas should be allocated in advance, probably during initialization. The immediate data, which must be copied to device driver buffer space, should be copied using a double word copy. Additionally, the destination buffer for the immediate data should be double word aligned. The number of transmission commands to the adapter should be minimized, though achieving this goal is adapter dependent. There is a performance benefit when several TransmitChains in a row are issued to the MAC driver. Finally, as mentioned in the previous section, high priority must be given to detecting previously submitted frames have been transmitted. If this check is made, then these TransmitConfirms for these frames can be issued directly within the TransmitChain path.
The NDIS specification also provides a performance recommendation for TransmitChain. In the introduction to Chapter 5 of 3Com/Microsoft LAN Manager Network Driver Interface Specification, the following can be found. "It is recommended that a MAC release the internal resources associated with either TransmitChain or a request before calling the confirmation handler. This allows the protocol to submit a new TransmitChain or request from the confirmation handler. Failure to do so may have a significant impact on performance."
TransferData
The TransferData primitive is issued by the protocol to the MAC device driver during a ReceiveLookAhead. The protocol asks the MAC device driver to copy the received data into the buffer spaces specified in a list of data blocks. The key to this routine is setting up the source and destination selectors and deciding how much data to copy. This process may be repeated many times depending upon how many data buffers the received data is stored in and how many buffers it is being transferred to. Each copy should be done using a double word copy. If the received data is in device driver buffers, then they should be double word aligned for fastest copy time. Tied in with these techniques is a suggestion for use in the ReceiveLookAhead routine, which will occur on interrupt. The lookahead buffer that is passed to the protocol should be the actual buffer into which the adapter has placed the data. The idea is to avoid allocating separate lookahead data buffers and the subsequent need to copy data into them. Further, in this method the lookahead buffer can potentially contain the entire frame, eliminating the need for the protocol to issue a TransferData primitive call.
TransmitConfirm
The TransmitConfirm primitive is issued by the MAC device driver to the protocol to indicate completion of a previous TransmitChain. This call serves an important function as an asynchronous indication to the protocol that the MAC device driver is ready to process additional transmit requests. A possible pitfall in NDIS MAC device driver design is to try to eliminate the need for TransmitConfirm calls. This can the done by returning 'success' to the protocol upon TransmitChain. This approach seemingly saves MAC device driver to protocol interactions. However, it may backfire in the following manner. Since the MAC device driver is actually queuing transmit requests internally and not completing them, when it runs out of transmit resources it will be forced to return 'out_of_resource'. This, in turn, will force the protocol to poll the MAC device driver to find out when resources are available again. The protocol must poll since no asynchronous indication, i.e. TransmitConfirm, will be forthcoming from the MAC device driver. Choosing the right polling interval is an intractable problem. If the interval chosen is too short, too much CPU is utilized. If the interval chosen is too long, the protocol will lose synchronization with the MAC device driver and not be passing it data as often as it could. Either way, serious throughput and overall performance degradation may occur. As a result, we strongly recommend that NDIS MAC device drivers use the TransmitConfirm primitive.
Interrupt Processing
The interrupt routine is critical to NDIS MAC device driver performance. Any excessive time spent in the interrupt handler can adversely affect performance. The two goals for an efficient interrupt handler are to minimize the number of interrupts (i.e. the number of times the operating system calls the interrupt handler) and to minimize the time spent processing each interrupt.
The two most common reasons for entering the interrupt routine are the "reception of data and notification of a completed transmission. Adapters may also interrupt the device driver if needed system resources, such as buffer space for DMA, have been depleted. NDIS primitives which the MAC device driver may issue to the protocol on interrupt include TransmitConfirm, ReceiveLookAhead, ReceiveChain, and StatusIndication. The IndicationComplete may be issued on interrupt when running OS/2, but not when running DOS.
There are a few general performance guidelines for efficient interrupt processing. We list them here and then conclude this section with several more specific suggestions for improving performance. The interrupt handler is a time critical routine in and of itself. Interrupts should not remain masked for more than approximately 500 microseconds. This means that the End of Interrupt should be issued to the interrupt controller within 500 microseconds of entry into the device driver's interrupt handler. The MAC driver interrupt handler must perform the following actions before issuing the end of interrupt:
- determining if the interrupt is for this MAC driver
- masking the adapter to prevent further interrupts
- reading any adapter unique status which may be overwritten, and hence lost, due to subsequent events.
Only useful and necessary processing should take place on interrupt. Necessary processing includes time critical adapter interfacing, such as rearming the adapter. In addition, to reduce the overhead inherent in processing interrupts, the interrupt handler should check for additional work before exiting. This decreases latency and reduces CPU utilization by lessening costly context switches back to the operating system.
As mentioned above in the Performance Issues in NDIS MAC Device Driver Design section, the interrupt handler must balance processing efficiently with the need to detect higher priority work. Once the interrupt handler is in control through an interrupt driven event, further interrupts from the adapter should be masked until all work discoverable by checking adapter status has been completed. This will minimize kernel interrupt processing overhead.
The interrupt handler must also balance its processing between handling transmit completes and handling received data. As indicated previously, the balance that must be maintained between keeping the adapter as busy as possible with data to be transmitted and keeping the protocol as busy as possible processing received data. One way to achieve this balance is to limit the number of transmit completes to process before checking for higher priority interrupt and receive frame processing.
OS/2 System Service Usage
Device drivers need to use OS/2 system services to access functions such as memory allocation and address translations. The high performing NDIS MAC device driver will need to limit the use of OS/2 system services, particularly on the critical transmit and receive paths. A discussion of these critical paths can be found in the previous two sections of this document. Limiting operating system usage to only necessary calls will both reduce path length and lessen CPU utilization. One way this may be achieved is to save useful results obtained via system calls, eliminating the need to repeat the call later. Address translations are a good example of calls to which this technique applies.
One specific piece of advice relating to use of system services comes from the OS/2 device driver reference manuals. It is stated there that a device driver strategy routine should be prepared to yield the CPU about every 3 milliseconds. Limiting system service call will help ensure adherence to this rule.
Programming Practices
This document has detailed a number of ideas which improve the performance of NDIS MAC device drivers. However, the fundamental method for producing high performing code is writing efficient code. In that sense, the tips and techniques which we will summarize in this section underlie every other section of this guide.
The ideas in this section all fall under the general heading of code tuning. The goals of code tuning are to:
- decrease the number of processor cycles required by program
- decrease the number of address calculations performed
- decrease the number of memory fetches
- decrease the size of object code.
The major way to eliminate address calculations and memory fetches is by alignment. With the Intel 80386 and successor architectures, the normal memory fetch is for a double word (four eight bit bytes) of data, aligned on a double word boundary. Hence, proper alignment of any memory will optimize fetch performance, while misalignment will degrade performance. The only exceptions to this rule are possible overrides by the memory management system of the processor for devices whose bus access is fewer than 32 bits wide. Even for those devices, access will almost surely be at a word granularity and following double word alignment guidelines would not degrade performance.
The most important items to align are data structures. The rules to follow are:
- align the data structure on a double word boundary. This means that the starting (physical) address of the structure should be on a four byte boundary.
- elements of the data structure containing four or more bytes should be started on double word boundaries.
- elements of the data structure containing fewer than four bytes should not cross double word boundaries.
Achieving alignment for each element in a data structure may require reordering the elements and the addition of null elements.
Code itself may also be aligned. The most important instructions to align are the targets of jump instructions. These instructions may be double word aligned by using an assembler directive which will automatically generate any needed null, aligning, instructions.
Data copying is one of the most CPU intensive operations. The time to copy data depends upon three factors: the granularity of the move instruction (byte, word or double word), the alignment of the source buffer and the alignment of the target buffer. The fastest copy time is achieved when both buffers are double word aligned, and the double word move instruction (REP MOVSD) is used. If either buffer is not double word aligned, the following technique produces an efficient string move routine. First, copy up to three bytes until the destination address is double word aligned. Second, copy the remaining bytes using the double word string copy instruction. Use of the double word copy move instruction ensures the smallest overhead for data transfer.
Two other suggestions may also help speed up code execution. The first is to order tests so that jumps are to the least likely cases. This ensures that the less costly fan through case (no jump) is to the most likely case. This also assumes that the code can be structured so that there is no jump instruction at the end of the code for the most likely case. It may be difficult to structure the code in this manner. The second suggestion is to take advantage of the 32 bit nature of the Intel 80386 (and successor) chips. One major advantage of the 80386 architecture over the 80286 architecture is the inclusion of too additional segment registers. Careful use of these registers will eliminate unnecessary and costly segment register loads. The additional high order word provided in each general purpose registers may also be used to lessen accesses to secondary memory.
We conclude this section by summarizing a number of the points made in an invaluable book. The book is "Writing Efficient Programs" by Jon Louis Bentley (1982, Prentice-Hall). The rules in the book are general in nature and their indiscriminate application is strongly discouraged. In addition, always keep in mind that the efficiency of a program is secondary to its correctness. Once again, there are two main areas where modifications may improve the efficiency of a program: in the data structures and in the code.
Data structures can be either modified or completely replaced. The latter approach is a system design issue and is not germane to the current discussion. Simple modifications to data structures can help reduce a program's time and/or space. Bentley suggests four methods for trading off more space for less time.
- Data Structure Augmentation This refers to either adding additional information in the structure to or to changing the structure so its components can be accessed more easily. Data structure alignment, discussed above, is an example of this method.
- Store Precomputed Results This should be done to save the cost of recomputing an expensive function. Storage of results of OS/2 system service calls fall into this category.
- Caching Data that is accessed most often should be cheapest to access. Proper use of the two extra segment registers found in the 80386 chip, as opposed to only using 80286 registers, would be an example of this rule.
- Lazy Evaluation This idea is to only evaluate expressions when necessary, thereby avoiding unneeded work.
It is possible to speed up small pieces of code by making local transformations. These changes fall into four general categories: loops, logic, procedures, and expressions. The referenced book contains a clear and concise discussion of rules to apply in these categories; we shall not repeat it here. Rather, we close by listing four fundamental rules which underlie all of the suggestions for writing efficient programs. These fundamental rules are (excerpted from pages 104 and 105 of Bentley):
- Code Simplification Most fast programs are simple. Therefore keep code simple to make it faster.
- Problem Simplification To increase the efficiency of a program, simplify the problem it solves.
- Relentless Suspicion Question the necessity of each instruction in a time-critical piece of code and each field in a space-critical data structure.
- Early Binding Move work forward in time. Specifically, do work now just once in hopes of avoiding doing it many times later.
Notices
May 1993
The following paragraph does not apply to the United Kingdom or any country where such provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this statement may not apply to you.
This publication could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; these changes will be incorporated in new editions of the publication. IBM may make improvements and/or changes in the product(s) and/or program(s) described in this publication at any time.
It is possible that this publication may contain reference to, or information about, IBM products (machines and programs), programming, or services that are not announced in your country. Such references or information must not be construed to mean that IBM intends to announce such IBM products, programming, or services in your country.
Copyright Notices
© Copyright International Business Machines Corporation 1993. All rights reserved.
Note to U.S. Government Users - Documentation related to restricted rights - Use, duplication or disclosure is subject to restrictions set forth in GSA ADP Schedule Contract with IBM Corp.
Disclaimers
References in this publication to IBM products, programs, or services do not imply that IBM intends to make these available in all countries in which IBM operates. Any reference to an IBM product, program, or service is not intended to state or imply that only IBM's product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any of IBM's intellectual property rights or other legally protectible rights may be used instead of the IBM product, program, or service. Evaluation and verification of operation in conjunction with other products, programs, or services, except those expressly designated by IBM, are the user's responsibility.
IBM may have patents or pending patent applications covering subject matter in this document. The furnishing of this document does not give you any license to these patents. You can send license inquiries, in writing, to the
IBM Director of Commercial Relations,
IBM Corporation,
Purchase, NY 10577.
Trademarks
The following terms, denoted by an asterisk (*) in this publication, are trademarks of the IBM Corporation in the United States and/or other countries:
IBM | OS/2 | Extended Services |
The following terms, denoted by a double asterisk (**) in this publication, are trademarks of other companies as follows:
Microsoft | Microsoft Corporation |
3Com | 3Com Corporation |
CompuServe | CompuServe Incorporated |
All other company, brand, and product names are trademarks or registered trademarks of their respective owners.
- NDIS Driver Developer's Tool Kit for OS/2 and DOS - Random Redirected Transform Test User's Manual
- LAN Adapter and Protocol Support - IBM Product Overview
IBM NDIS Driver Implementation Package
Description/Contents
The IBM LAN Adapter and Protocol Support (LAPS), Network Transport Services/2 (NTS/2), and the DOS LAN Support Program (LSP) are the communications subsystems for IBM OS/2 and DOS products that require LAN connectivity. LAPS is included in the following products: Extended Services 1.0 (with or without Database Manager); LAN Server 2.0 (Entry or Advanced); LAN Enabler 2.0; TCP/IP v. 1.2.1; LAN Server 3.0 (Entry or Advanced) and NTS/2 1.0. In LAPS, NTS/2 and LSP, the Network Driver Interface Specification (NDIS) architected interface has been implemented for enabling NDIS Media Access Control (MAC) Device Drivers. This will allow the support of IEEE 802.5, 802.3, and Ethernet DIX Version 2.0 NDIS MAC drivers. This includes support for Ethernet, Token-Ring, FDDI, PCnet, and other architected network technologies.
If your organization has an adapter that you want supported on a platform containing the IBM LAPS and LSP, you will have to provide the NDIS MAC Device Driver for that adapter, and a Network Information File (NIF) for the install process. For OS/2 it is strongly recommended that a message file and message help file also be included.
Enclosed in this package are documents that are designed to assist you in the implementation of a new NDIS MAC Device Driver, or the conversion of an existing NDIS MAC Device Driver. These documents include the following:
- 3Com*/Microsoft LAN Manager** Network Driver Interface Specification Version 2.0.1 Final
- LAN Adapter and Protocol Support IBM Product Overview
- IBM OS/2 LAN Server 3.0 Product Overview
- IBM Network Transport Services/2 Version 1.0 Product Overview
- NDIS Implementation Information for IBM LAN Systems, NDIS Device Driver Requirements
- NDIS Implementation Information for IBM LAN Systems, Extended NIF Format
- NDIS Implementation Information for IBM LAN Systems, NDIS Extensions
- NDIS Implementation Information for IBM LAN Systems, OS/2 Messaging and National Language Support
- NDIS Implementation Information for IBM LAN Systems, IBM OS/2 LAN Technical Reference Extensions
- White Paper on NetBIOS Applications Interoperability
For more extensive assistance in developing an NDIS MAC driver for use with IBM LAPS and LSP, the DWB Associates NDIS Device Driver Toolkit for OS/2 and DOSis available from DWB Associates, Inc. In addition to the documents you receive in this Information Package, the Tool Kit contains additional programming guides for writing NDIS MAC drivers and diskettes containing a sample driver, testing tools, test tool scripts, and a trace tool for debugging.
For information regarding the price and availability of the Tool Kit, contact DWB Associates, Inc., 9360 SW Gemini Drive, Beaverton, OR 97005, 503-626-3081.
- 3Com is a registered trademark of the 3Com Corporation
- Microsoft LAN Manager is a registered trademark of the Microsoft Corporation
Any reference to the NDIS Specification in products or documentation developed from this Implementation Package must contain the appropriate copyright and trademark acknowledgements.
May 1995
- NDIS Implementation Information for IBM LAN Systems - NDIS Device Driver Requirements
- IBM OS/2 LAN Server 3.0 Product Overview
- NDIS Implementation Information for IBM LAN Systems - IBM OS/2 LAN Technical Reference Extensions
- NDIS Driver Developer's Tool Kit for OS/2 and DOS TestTool User's Manual