Copyright (c) Hyperion Entertainment and contributors.
Revision 5
Contents
Hook-based callback function extensions for SANA-II (SANA-IIR5)
by Olaf Barthel and Heinz Wrobel
1. Introduction
The last changes proposed for the SANA-II networking driver standard were intended to address the demands of dial-up networking. A new issue has come up which concerns the application and deployment of PowerPC native networking drivers. So far the SANA-II standard only caters well for the Motorola 68000 platform, and the only way to support it on the PowerPC involves a considerable overhead. This is what the following proposal intends to address.
Please feel free to comment; you can contact me through the e-mail address given in the headline of this document. Note that the issues discussed in this document are just a list of proposed changes.
2. The problem: parameter passing to the copying functions
The SANA-II driver interface is intended to transform data between the hardware layer and the link layer, to be used by networking software such as TCP/IP stacks. This transformation is performed by call-back functions which are supplied by the networking software at the time the device driver is opened. The device driver then invokes these functions later in order to transfer data received and data to be sent.
These copying functions are designed for low overhead. They use up to three parameters and are documented in the copybuff.doc file which comes with the SANA-II specification. Here is an excerpt which describes the CopyFromBuff function, which is associated with the S2_CopyFromBuff tag:
any_sana2_protocol/CopyFromBuff any_sana2_protocol/CopyFromBuff NAME CopyFromBuff -- Copy n bytes from an abstract data structure. SYNOPSIS success = CopyFromBuff(to, from, n) d0 a0 a1 d0 BOOL CopyToBuff(VOID *, VOID *, ULONG); FUNCTION This function copies 'n' bytes of data in the abstract data structure pointed to by 'from' into the contigous memory pointed to by 'to'. 'to' must contain at least 'n' bytes of usable memory or innocent memory will be overwritten. INPUTS to - pointer to contiguous memory to copy to. from - pointer to abstract structure to copy from. n - number of bytes to copy. RESULT success - TRUE if operation was successful, else FALSE. NOTES This function must be callable from interupts. In particular, this means that this function may not directly or indirectly call any system memory functions (since those functions rely on Forbid() to protect themselves) and that you must not compile this function with stack checking enabled. See the RKM:Libraries Exec:Interupts chapter for more details on what is legal in a routine called from an interupt handler. 'C' programmers should not compile with stack checking (option '-v' in SAS) and should geta4() or __saveds.
As one can see, the function parameters are passed in 68000 registers. Compare this to the packet filter function, which is associated with the S2_PacketFilter tag: it is intended to be invoked as a hook function, as part of the Hook interface in utility.library/CallHookPkt.
The problem with 68000 register parameters is that on the PowerPC platform, this form of parameter passing may require the use of emulation code. This is costly and may incur a severe performance penalty. It is an even greater problem if PowerPC native networking software is calling PowerPC native networking driver software and the other way round. In both cases the runtime environment will have to enter emulation mode, return to to PowerPC native execution, dip into emulation mode and return to native PowerPC execution. It would be much better if the chain of execution would stay in PowerPC mode all the time.
However, if a hook function is used (such as for the packet filter), the operating system may be able to decide whether the function to be invoked needs emulating or could be called straight away. The Hook effectively works as an abstraction which makes the function invocation platform independent.
The following proposal therefore intends to wrap the copying functions into the standardized Hook interface.
3. New data structures and commands
3.1 Data structures
The SANA-IIR4 proposal lists ten copying functions, which can be grouped into two categories: data copying and direct memory access. These functions are:
- Data copying:
- S2_CopyToBuff
- S2_CopyFromBuff
- S2_CopyToBuff16
- S2_CopyFromBuff16
- S2_CopyToBuff32
- S2_CopyFromBuff32
- Direct memory access:
- S2_DMACopyToBuff32
- S2_DMACopyFromBuff32
- S2_DMACopyToBuff64
- S2_DMACopyFromBuff64
There are three 'flavours' of the data copying functions. These cater for certain buffer memory alignment requirements which the underlying hardware requires or which can be used to boost transfer efficiency. For the direct memory access functions there are two variants which cater for certain memory alignment requirements in the same manner as the copying functions.
All these functions are using basically the same set of parameters and 68000 registers. The parameters and result codes are used for different purposes, though. In order to translate the parameters for use with the Hook interface one needs to define a 'hook message' and a set of parameters the hook function is invoked with.
I propose the following hook messages to be used :
struct SANA2HookMsg { ULONG shm_Method; ULONG shm_MsgSize; };
In this data structure the shm_Method field would indicate the task to be performed. This can a be request to copy data or to store a log message. The shm_MsgSize field tells you how large the data structure is (for future enhancements which may cause the data structure to grow).
For copying operations the message would look like this:
struct SANA2CopyHookMsg { ULONG schm_Method; ULONG schm_MsgSize; APTR schm_To; APTR schm_From; ULONG schm_Size; };
The structure members would be used as follows:
schm_Method
This must be one S2_CopyToBuff, S2_CopyFromBuff, S2_CopyToBuff16, S2_CopyFromBuff16, S2_CopyToBuff32, S2_CopyFromBuff32, S2_DMACopyToBuff32, S2_DMACopyFromBuff32, S2_DMACopyToBuff64 or S2_DMACopyFromBuff64 to identify the function to be performed.
schm_MsgSize
Size of this message data structure in bytes. This must be >= 20 for this message type.
The driver shall set schm_MsgSize always correctly to be compliant. The protocol stack shall use this field to validate the message and to reject/ignore bad messages via a FALSE hook function return value. For DMA related hooks, a FALSE return value is equivalent to a NULL pointer.
schm_To
Equivalent to the to parameter of the CopyFromBuff, CopyToBuff and DMACopyToBuff functions.
schm_From
Equivalent to the from parameter of the CopyFromBuff and CopyToBuff functions.
schm_Size
Equivalent to the n parameter of the CopyFromBuff, CopyToBuff, functions.
For logging operations the message would look like this:
struct SANA2LogHookMsg { ULONG slhm_Method; ULONG slhm_MsgSize; ULONG slhm_Priority; STRPTR slhm_Name; STRPTR slhm_Message; };
The structure members would be used as follows:
slhm_Method
This must be S2_Log, as defined in the SANA-IIR4 specification.
slhm_MsgSize
Size of this message data structure in bytes. This must be >= 20 for this message type.
The driver shall set slhm_MsgSize always correctly to be compliant. The protocol stack shall use this field to validate the message and to reject/ignore bad messages via a FALSE hook function return value. For DMA related hooks, a FALSE return value is equivalent to a NULL pointer.
slhm_Priority
The smaller this value, the more important the message to be logged or displayed. The following priority levels are defined (similar to the Unix syslog() mechanism):
#define S2LOG_Emergency 0
A panic condition.
#define S2LOG_Alert 1
A condition that should be corrected immediately.
#define S2LOG_Critical 2
Critical conditions.
#define S2LOG_Error 3
A plain error.
#define S2LOG_Warning 4
A warning message.
#define S2LOG_Notice 5
Conditions that are not error conditions, but should possibly be handled specially.
#define S2LOG_Information 6
An informational message.
#define S2LOG_Debug 7
Messages that contain information normally of use only when debugging.
Only these priority values may be used by a driver. It is suggested that a driver is configurable to generate different types of messages or not, e.g., a driver may be configured to only emit S2LOG_Emergency and S2LOG_Debug messages.
slhm_Name
Pointer to a NUL-terminated string which identifies the source of this message. This can be NULL in which case the OS device name of the driver shall be used by the protocol stack.
slhm_Message
Pointer to a NUL-terminated string which contains the log message. The text should not contain any formatting characters such as line feeds or carriage returns. The slhm_Message member must never be NULL.
All message texts shall preferrably be formatted in the current user's locale. If that is not possible, the english language shall be used. slhm_Name and slhm_Message shall only contain printable characters.
The hook function itself would be invoked with the following parameters:
result = hook_function(hook,sana2req,sana2hookmsg) D0 A0 A2 A1 ULONG hook_function(struct Hook *hook, struct IOSana2Req *sana2req, struct SANA2HookMsg *sana2hookmsg);
Note that the result would not necessarily be of type ULONG. It would be a 32 bit value, which would either be a boolean result code (for CopyFromBuff, CopyToBuff and their like) or the pointer to a memory address (for DMACopyToBuff, DMACopyFromBuff and their like).
3.2 Commands
The 'traditional' copy call-back functions are installed at OpenDevice() time, and they are found in a TagItem list which is passed along with the IOSana2Req. For the new Hook-based call-back functionality, I propose to introduce a new command. This command would take care of installing one single Hook which will be invoked with the parameters described in section 3.1. The hook function can key off the SANA2HookMsg->schm_Method field to figure out which function should be performed. Once the Hook is installed via the command as follows, the driver shall ignore any and all tags passed to it during OpenDevice() time.
The command is tentatively defined as follows:
sana2.device/S2_SANA2HOOK sana2.device/S2_SANA2HOOK NAME S2_SANA2HOOK -- Install a Hook to perform operations such as copying, overriding the call-back functions installed at OpenDevice() time. FUNCTION The S2_SANA2HOOK command is to replace the 'traditional' call-back functions installed through the TagItem list found in the IOSana2Req->ios2_BufferManagement field. Instead of assigning a function pointer for each copying function, all operations are to be performed through a Hook. This is intended to make the interface more portable and less dependant on a certain hardware architecture. The hook message and the hook data structures allow for more than copying to be done. IO REQUEST ios2_Command - S2_SANA2HOOK ios2_Data - Points to a struct Sana2Hook, which looks like this: struct Sana2Hook { struct Hook s2h_Hook; Tag * s2h_Methods; }; The structure fields have the following purposes: s2h_Hook A standard Hook structure, ready to be called. Once installed, the complete Hook structure including its Node structure is off limits! The s2h_Hook remains installed until CloseDevice(). s2h_Methods Points to a table of Tag values, each identifying a copy method supported (S2_CopyToBuff, S2_CopyFromBuff, S2_CopyToBuff16, S2_CopyFromBuff16, S2_CopyToBuff32, S2_CopyFromBuff32, S2_DMACopyToBuff32, S2_DMACopyFromBuff32, S2_DMACopyToBuff64 or S2_DMACopyFromBuff64) or the logging facility (S2_Log). The table must be terminated by TAG_END. The driver will check the table and verify that the mandatory S2_CopyToBuff and S2_CopyFromBuff commands are present. Additional functionality is used as available if the driver supports it. ios2_DataLength - Must be >= 20, which is the default length of the Sana2Hook structure. This may grow in the future, and larger values for ios2_DataLength may indicate additional functionality associated with the Sana2Hook. RESULTS ios2_Error - IOERR_NOCMD if this command is not supported by the driver. IOERR_BADLENGTH if IOSana2Req->ios2_DataLength is < 20. IOERR_UNITBUSY if the Hook was already installed or if any of the CMD_READ, CMD_WRITE, S2_MULTICAST or S2_BROADCAST have already been invoked. S2WERR_FUNCTIONS_MISSING if the table pointed to by Sana2Hook->s2h_Methods does not include the S2_CopyToBuff and S2_CopyFromBuff tags. NOTES The S2_SANA2HOOK command shall be invoked right after OpenDevice() as very first command. When the command has been executed, the driver must use the newly installed Hook for all its copying or logging and cease to use the call-back functions provided at OpenDevice() time. The contents of the Sana2Hook structure, as passed to the driver, must not be modified. This includes the MinNode at the beginning of the Hook structure which the driver may need to use for its own purposes. The table pointed to by Sana2Hook->s2h_Methods must include at least the S2_CopyToBuff and S2_CopyFromBuff tags. It must be valid until CloseDevice() is called. This field is to be treated as private by a protocol stack. IOSana2Req structures may be duplicated by copying ios2_BufferManagement, io_Device, and io_Unit.
The new command value is defined as follows:
#define S2_SANA2HOOK 0xC008
The new error code is defined as follows:
#define S2WERR_FUNCTIONS_MISSING 24 /* mandatory copy functions are missing */
4. Application and driver software use of the new functions
Since plenty of software exists which uses the 'traditional' TagItem list provided at OpenDevice() time it is recommend that drivers always examine these parameters and do not expect a S2_SANA2HOOK command to be sent later.
If the new Hook-based callback functions are to be used, then the driver must invoke the Hooks via utility.library/CallHookPkt. It must not invoke the hook functions through local assembly language stubs or the amiga.lib/CallHook and amiga.lib/CallHookA functions.
5. Caveats
The functionality proposed above suggests that one could do entirely without the TagItem list passed in at OpenDevice() time. However, at this time it is hard to tell how existing driver software will react to empty TagItem lists or even a NULL pointer in the IOSana2Req->ios2_BufferManagement field. It is therefore recommend to always provide for a TagItem list which includes proper (i.e. they must point to working functions and may not be NULL) function pointers for the S2_CopyToBuff and S2_CopyFromBuff tags. Once the device has been opened successfully, the next step is to try and install the copy Hook through the proposed S2_SANA2HOOK command. If the command fails, the application can still expect that the S2_CopyToBuff and S2_CopyFromBuff tags supplied at OpenDevice() time will work.
Note that the ios2_BufferManagement field provided by the driver on OpenDevice() time in conjunction with io_Device and io_Unit is the unique identifier for all requests coming from this protocol stack until CloseDevice(). The driver must not ever change the ios2_BufferManagement field for a protocol stack at run time, even if S2_SANAHOOK is called to request extended features.
6. Changes
22-Mar-2004:
- Conversion to HTML
21-Jan-2004:
- Added clarifications for schm_MsgSize, slhm_MsgSize, slhm_Priority, slhm_Name, slhm_Message and s2h_Hook.
- Updated the S2_SANA2HOOK documentation.
- Shortened section 4.
- Updated section 5.
30-Nov-2003:
- Extended the applicability of the Hook to logging.
- Renamed S2_COPYHOOK to S2_SANA2HOOK, which matches the extended scope it should cover.
- The message passed to the Hook now includes a size field which holds the size of the message, expressed in bytes.
06-Oct-2003:
- Replaced the list of new tag items with a single Hook, which is installed through a new command.
- Added "Caveats" and "Changes" sections
- Removed the documentation for the originally proposed TagItem (sections 3.2.1 through 3.2.10)