Category Archives: os/2

DevHlp_Security

Description

This is the kernel support for the security enabling services.

Calling convention

Subfunction: DHSEC_SETIMPORT
This function will load the ISS Security Event Service Routine Table into the kernel. Each service routine will be called upon a certain API event, such as opening a file, or starting a program. There are also service routines to capture each DOS API routine (if you are interested in this, and you are considered trustworthy by me, i.e. well-known in the OS/2 hacker’s scene, I can give you code for these rather tricky routines – collectors and gatherers stay off!).

  • EAX = 073ae3627h special function key
  • ECX = FLAT (linear) address of table to be submitted
  • DL = 044h

Subfunction: DHSEC_GETEXPORT
This function will return the table of security helper functions for file access. These helpers provide low level access to any file in the system which is not controlled by security services (unlike the normal DOS API).

  • EAX = 048a78df8h special function key
  • ECX = FLAT (linear) address of a buffer to receive the 40 byte table
  • DL = 044h

Subfunction: DHSEC_GETINFO
Internally used function, information withheld intentionally.

Subfunction: DHSEC_AUDITHOOK
Internally used function, information withheld intentionally.

Subfunction: DHSEC_TRUSTEDPATHNOTIFY
Internally used function, information withheld intentionally.

Subfunction: DHSEC_IMPORT_PDF
Special purpose function for an IBM product, information withheld intentionally.

Subfunction: DHSEC_IMPORT_AV
Special purpose function for an IBM product, information withheld intentionally.

Returns

  • CY=0, AX = 0, okay
  • CY=1, AX = APIRET error code

Data structures

It is beyond the scope of this text to explain all details of SES. Consult the Red Book SG2446-68, also available via DevCon. IBM has decided, as of SG2446-68, appendix A, not to publish the SES KPI. You can ask, according to the Red Book for this documentation at:

IBM Manager of OS/2 Security
Mail Stop 9171
11400 Burnet Rd.
Austin, Texas 78758
(is this address still valid?)

Restrictions

Valid at any time.

DevHlp_OpenFile

Description

This devhlp allows to open a file for read access in the Init routine of a BASEDEV.

Calling convention

ES:DI = point to a SYIOpenFile structure

  • DL = 07fh

Returns

  • CY=0, AX = 0: okay, structure pointed to by ES:DI is modified
  • CY=1, AX = ERROR_BAD_LENGTH: packet is invalid
  • CY=1, AX = <>0: other filesystem related errors

Data structures

; assembler structure
SYIOpenFile struc
length		dw	8	; length of structure, must contain value 8
name		dd	?	; 16:16 ASCIZ pathname
fsize		dd	?	; returned: size of file
SYIOpenFile	ends

Restrictions

Valid at INIT time only. This routine is not handle based, so it is only possible to have only one file at a time open. This routine uses the corresponding function of the miniFSD, not normal file I/O, thus access is restricted. At this phase of boot, drive letters do not yet exist, and IFSs/DMDs might not yet have been initialized, so you can only open files on the boot drive. Depending on the type of IPL (e.g. loading from a network file system), other restrictions might apply.

Bugs

The returned file size is unreliable, the value returned is always

Republished without permission from Holger Veit’s long gone webpages – MKG

OS/2 Device Drivers for Dummies – The Beginning

Last change 09/05/2007

1. Introduction

Let me first state that I fully intend to plagiarize as much as possible, deal with it. There seems to be only a few options for the hobbyist programmer to easily learn how to build a device driver for eCS-OS/2. Some good examples that exist are Alger Pike’s EDM/2 articles from years ago, so they are somewhat dated. Another example is contained in the Open Watcom directory [samples\os2\pdd]. Of course there are various driver examples available from many additional sources, just use Google. This text deals with 16 bit eCS-OS/2 drivers.

I am using several printed and electronic text references which can be be found both online or through book sites such as Amazon.com:

  • 1. OS/2 Physical Device Driver Reference
  • 2. Design of OS/2 by Harvey M. Deitel and Michael S. Kogan (note 1)
  • 3. Writing OS – 2 2.1 Device Drivers in C by Steven J. Mastrianni (note 2)
  • 4. Device driver information contained on the second eCS CD
  • 5. Writing OS/2 Device Drivers by Raymond Westwater

Reference 3 and 5 are very good, but only deal with 16 bit drivers. However, there is rumored to be an unpublished version of reference 3 for OS/2 Warp (1997) floating around the net somewhere. I will be taking parts of all the above and with luck provide something that can be used to learn what I did much quicker for a beginner.

You need some knowledge of C and enough ASM know-how to understand some basic source. For ASM I know how to do a HelloWorld executable but that is the extent. Also, the current version of Open Watcom needs to be installed and working. Later you might want to read up on privilege levels and a good explanation exists on EDM/2 by Holger Veit (what happened to him?).

I have modified Pike’s Hello World example so it can be compiled with Open Watcom and does not require the OS/2 DDK [here]. It outlines the basic parts of a device driver, but really does nothing. During system boot it displays a message which indicates it has loaded and executed initialization. I have provided a test.exe which when run opens and closes the driver. The driver will beep on open and close, not very exciting but it does provide feedback that things are working correctly.

What is the most important thing to remember? Nothing comes fast and easy and the following information is from my continued learning about device drivers. I started with no knowledge and am still very limited. The source code for the driver and test program are HERE. Enjoy…

Note 1: I believe there are PDF versions of this book floating around, I have a hard cover copy. However, I did email Dr. Kogan asking if he would release it to the masses. He reply that he had wanted to do this sometime ago, but his coauthor would not agree to it.

Note 2: I know there is an unpublished 3rd revision PDF floating around which covers Warp (approx 1997).

2. What is a Device Driver?

Exactly what is a device driver? Simply put, a device driver is a piece of code which is dedicated to controlling a particular device. It is the device dependent module that provides the low-level I/O and interrupt support for a device. Also, the device driver will manage any memory that the device may use for Direct Memory Access. The device can be anything from a video card to a data acquisition board. A driver is necessary because many of the previous operations must occur at ring level 0 for them to be successful under eCS-OS/2, and for code to run in ring 0, it must be in a device driver. So, device drivers are trusted modules that have access to the kernel. For the hobbyist programmer this means you can really crash the system now!

Device drivers come in two flavors, block and character. Block devices are used for mass storage devices and character devices handle data one character at a time. Is this true? I have read that it is so, most of the time. However, in Gordon Letwin’s Inside OS/2 he says the following:

OS/2 device drivers are divided into two general categories: those for character mode devices and those for block mode devices. This terminology is traditional, but dont take it too literally because character mode operations can be done to block mode devices. The actual distinction is that character mode device drivers do I/O synchronously; that is, they do operations in first in, first out order. Block mode device drivers can be asynchronous; they can perform I/O requests in an order different from the one I which they received them.

Device drivers operate in three different modes: INIT, Kernel (or task), and Interrupt. INIT mode is a special mode executed during at system boot with RING 3 privileges, however, it is allowed some RING 0 privileges (see OS/2 PDD reference). The Kernel mode is in effect when the device driver is called by the kernel in response to an I/O request. The Interrupt mode is in effect when the device driver’s interrupt handler is called in response to an external interrupt. In this example I will only be concerned with INIIT and Kernel modes.

I intend only to deal with 16-bit driver and not some of the 32-bit additions IBM added.

So, where does this all start? During system boot time the kernel finds a DEVICE= statement in the CONFIG.SYS file and then loads the device driver. Next, it reads the device driver header which is where I start this adventure.

3. The Header

The device driver consists of at least one code segment and one data segment, although more memory can be allocated if required. Additionally, the device driver is an EXE type program which is linked as a DLL. The header contains information used by the kernel during initialization. The data segment, which contains the Device Header, must appear as the very first data item. No data items or code can be placed before the Device Header. An OS/2 device driver which does not adhere to this rule will not load. While I do not intend to get ASM deep, the devsegs.asm source and #pragma data_seg ( “_HEADER”, “DATA” ) in header.c keeps the segments in order.

The initialization thread opens the driver module and reads the first segment into low memory (below 1M). This segment will be the main data segment. The second segment is loaded into low memory and will be the main code segment. Any additional segments are read into high memory (above 1M).

device segments
The device header is defined in devhdr.h:

typedef struct DEVHEADER DEVHEADER;
struct DEVHEADER {
  struct DEVHEADER FAR *next;      // next driver in chain
  uint16_t         DAWFlags;       // device attribute word
  NPVOID           StrategyEntry;  // offset to strategy routine
  NPVOID           IDCEntry;       // offset to IDC routine
  uint8_t          Name[8];        // driver name
  uint16_t         DAWProtCS;      // * Protect-mode CS of strategy entry pt
  uint16_t         DAWProtDS;      // * Protect-mode DS
  uint16_t         DAWRealCS;      // * Real-mode CS of strategy entry pt
  uint16_t         DAWRealDS;      // * Real-mode DS
  uint32_t         Capabilities;   // Capabilities bit strip
};

This Hello World header is defined in header.c with the following values:

DEVHEADER DDHeader = {
	-1L,                                         // Link to next header in chain
	DAW_CHARACTER|DAW_OPENCLOSE|DAW_LEVEL1,      // device attribute word
	Strategy,                                    // Entry point to strategy routine
	0,                                           // Entry point to IDC routine
	{"Hello$  "},                                // Device driver name
	0,0,0,0,                                     // Reserved
	CAP_NULL                                     // Capabilities bit strip (for level 3 DDs)
};

The “next driver in chain” link is set to -1L to mark the end of DEVHEADER chain (see devhdr.h) because the example device driver contains only a single device. If a second device were to be defined in this driver then the field would point to it. Next, the Device Attribute Word which is used to define the operational characteristics of the device driver. This is set to DAW_CHARACTER | DAW_OPENCLOSE | DAW_LEVEL1 which are listed and explained in devhdr.h. The strategy routine entry point is next and is explained in section 4 of this article. The IDC entry point offset follows and is used if the device driver supports inter-device driver communications. The Hello World driver does not support IDC so this is set to 0. The Device driver name is next and must be 8 characters in length, notice how the Hello$ name is padded with spaces. The final field is the Capabilities Bit Strip word defines additional features on level 3 drivers (OS/2 v2.0 (support of memory above 16MB). See devhdr.h for Capabilities Bit Strip options, however, the Hello World driver does not utilize level 3 options.

A more detailed description of the header is located here.

4. The Strategy Section

When I started, the title “Strategy” kind of scared me. Like most code, the name tends to scare a hobbyist programmer until one sees what it really is! The Strategy section is just a large switch statement and from my point of view the heart of the device driver. Remember, I am not covering interrupt drivers. The device driver receives a request from the kernel on behalf of the calling application which are passed to the Strategy. Also, the Strategy is called at initialization with RP_INIT which will execute the INIT routine. In the Hello World example the StratInit( ) funtion is called.

5. The INIT Mode

I would like to summarize what has been presented up to now. The kernel found a DEVICE statement during system boot, it loaded and then looked for the device header. It examines the header, finding the Strategy entry point (strategy.c) and the device name (Hello$). The kernel now calls the Strategy provided in the header with RP_INIT. To be more detailed and in Hello World context, it passes a request packet REQP_INIT (see devreqp.h) to the strategy entry point:

typedef struct _REQP_HEADER {
	uint8_t            length;        // Length of request packet
	uint8_t            unit;          // Unit code (B)
	uint8_t            command;       // Command code
	uint16_t           status;        // Status code
	uint32_t           res1;          // Flags
	struct REQP_HEADER FAR *next;     // Link to next request packet in queue
} REQP_HEADER;
typedef struct {
	REQP_HEADER header;
	union{
	    struct{
	        uint8_t   res;            // Unused
	        uint32_t  devhlp;         // Address of Dev Help entry point
	        int8_t    *parms;         // Command-line arguments   PCHAR
	        uint8_t   drive;          // Drive number of first unit
	    } in;
	    struct  {
	        uint8_t   units;          // Number of supported units
	        uint16_t  finalcs;        // Offset to end of code
	        uint16_t  finalds;        // Offset of end of data
	        void      *bpb;           // BIOS parameter block   PVOID
	    } out;
	};
} REQP_INIT;

On entry to Strategy( ) REQP_INIT rp->command will be set to RP_INIT which will call StratInit( ) to perform initialization. Again, it is important to remember during INIT the driver is actually at ring level 3 with some access ring level 0 functions. The following tables lists the API calls available at INIT:

DosBeep Generate sound from speaker
DosCaseMap Perform case mapping
DosChgFilePtr Change (move) file read/write pointer
DosClose Close file handle
DosDelete Delete file
DosDevConfig Get device configuration
DosDevIOCtl I/O control for devices
DosFindClose Close find handle
DosFindFirst Find first matching file
DosFindNext Find next matching file
DosGetEnv Get address of process environment string
DosGetInfoSeg Get address of system variables segment
DosGetMessage Get system message with variable text
DosOpen Open file
DosPutMessage Output message text to indicated handle
DosQCurDir Query current directory
DosQCurDisk Query current disk
DosQFileInfo Query file information
DosQFileMode Query file mode
DosRead Read from file
DosSMRegisterDD Register session switch notification
DosWrite Synchronous write to file

The initialization routine performs two important jobs. First, to save the value of the entry point for the device’s DevHlp routines (REQP_INIT rp->in.devhlp). Second, and to set the end of data and code segments (REQP_INIT rp->out.finalcs and REQP_INIT rp->out.finalds). The data and code segments after these points will be discarded after all device driver headers in the driver have been initialized. If the data length is set to zero then the driver will be unloaded.

I found the best simple explanation of the DevHlp entry point on USENET by Holger Veit:

“The kernel itself IS the device helper., i.e. when registering a device driver you get a 16:16 pointer to a kernel routine that is named DevHlp and all so called device helper functions call this entry point indirectly (after setting the appropriate registers).”

The DevHelp entry point should be declared as:

PFN  Device_Help  = NULL;

Although Resource Manager functions are not used in this Hello World example, you should plan for the future using Resource Management services. The PDD reference states: The PFN Device_Help variable must be initialized by your driver prior to calling any Resource Manager services. It is expected to contain the Device Help entry point provided in the OS/2 Init Request Packet your driver receives.

If the size of the segments remain zero, at the end of INIT the driver will unload.

6. The Kernel Mode

Need to add – MKG

7. Compiling and Testing the Driver

Compiling is easy. Ensure that Open Watcom is installed and working correctly. Unzip the hellowdevice.zip archive and then wmake. The result will be hello.sys and test.exe.

Here is the part where it all comes together! Place a statement in the config.sys (example: DEVICE=C:\hello.sys) and reboot. During boot you should see:

Hello World Driver Installed.
(C) ACP Soft 1996.
M Greene <greenemk@cox.net> 2007.
All Rights Reserved.

So, what just happened? The kernel found our DEVICE statement, loaded the driver, read the header, and then sent a RP_INIT to the Strategy Section. The Strategy Section received the RP_INIT and called the StratInit( ) function. The StratInit( ) function displayed the above message and returned. If the system did not hang or trap then hello.sys is loaded and ready.

As I stated, the driver does nothing spectacular. The test.exe executable interfaces with hello.sys to make some noise. When test.exe is run the following will be displayed with a couple beeps:

About to beep….
DosOpen return 0
Sleep for 5 seconds….
About to beep….
DosClose return 0

Ok, here is what just happened:

  • test.exe prints “About to beep” and issues a DosOpen to Hello$
  • The Strategy Section receives a RP_OPEN and executes the StratOpen( ) function
  • The StratOpen( ) function issues a DosBeep and RPDONE then returns
  • Now back in test.exe DosOpen return is printed with the return code
  • test.exe prints Sleep for 5 seconds and sleeps for 5 seconds
  • Next test.exe issues a DosClose to Hello$
  • The Strategy Section receives a RP_CLOSE and executes the StratClose( ) function
  • The StratClose( ) function issues a DosBeep and RPDONE then returns
  • Back in test.exe DosClose return is printed with the return code
  • test.exe exits

 

8. Summary

Exciting, right??? Well maybe not, but it is a good and simple drive driver example.

DevHlp_CloseFile

Description

This devhlp closes a file opened by DevHlp_OpenFile.

Calling convention

  • ES:DI = point to a SYICloseFile structure
  • DL = 080h

Returns

  • CY=0, AX = 0, okay
  • CY=1, AX = APIRET error code

Data structures

; assembler structure
SYICloseFile	struc
length		dw	2	; length of structure (must be 2)
SYICloseFile	ends

Restrictions

Valid at INIT time only. See also restrictions of DevHlp_OpenFile

DevHlp_KillProc

Description

This is a special entry into DosKillProcess, which is more rigid in killing processes: the killed process won’t be able to execute its kill signal handler, thus open files might not be closed properly. A process currently operating in ring 0 will terminate as soon as it returns to ring 3 (this means, a process blocked in the kernel, e.g. on a pending I/O, can still not be killed). This devhlp corresponds to the SESKillProcess API.
Calling convention

  • BX = Pid of process to kill, 0 = current process
  • DL = 07dh

Returns

  • CY=0, AX = 0, okay
  • CY=1, AX = APIRET error code

Data structures

None.

Restrictions

Valid at TASK time only.

Republished without permission from Holger Veit’s long gone webpages – MKG

 

The Warp Boot Sequence

Understanding the boot sequence of Warp is important to administrators and support personnel. It also helps to provide additional insight into the architechture of OS/2 Warp. Such an understanding will enable you to determine what can cause problems for your computer hardware as well as for Warp during boot.

Turning on the computer
When the computer is first turned on the power supply prevents the computer from taking any action by maintaining an electrical signal called “Power Good” in the off state until all power supply voltages have settled into the normal operational range. Only when the power supply is working correctly does it turn on the “Power Good” signal.
When the “Power Good” signal is turned on, some electronic circuitry in the computer sets the processor’s instruction pointer to the location in ROM BIOS which contains the POST program code. The computer loads the instruction at that location into the processor and starts the processor execution cycle. At this point the processor is in “Real” mode which means that it is effectively a fast 8086.
Power On Self Test
The Power On Self Test is located on a type of integrated circuit chip called Read Only Memory (ROM), along with some other programs such as BIOS. Power On Self Test (POST) is performed by most IBM PCs and PC compatible computers. POST is a critical part of the boot process because it provides some assurance that the hardware components of the computer are working correctly. Unfortunately, POST (and all DOS based diagnostic programs – there are no OS/2 based 32 bit diagnostic programs) is usually a 16 bit DOS class of program. It is therefore unable to test all aspects of a 32 bit computer. Even if POST or diagnostic programs were true 32 bit programs it would still be impossible to test every electronic circuit and component in a computer. At best a well written diagnostic program can only test about 80% of the components in a computer; POST, which is designed only to provide a quick check of the computer’s critical components does not even check that much. This means that there is still a good chance that a computer which passes both POST and diagnostics can still have a hardware defect which would cause problems with Warp or application programs.
POST first displays a count of installed memory as it performs a quick test of RAM. When that is complete you should see the total amount of RAM installed in your computer on the screen. Warp will recognize and utilize the amount of RAM displayed during the POST memory count.
If the memory count does not appear on the screen, it could be that the computer has been configured not to perform POST, the display is defective, or that the computer has a defective power supply. If the memory count does not show up on your screen, replace the display with one which is known to be good, and ensure that the computer has been configured to perform the POST. If that does not resolve the problem, replace the power supply.
POST then Initializes some interrupt vectors, and loads BIOS into RAM where it will perform better than if it were left in ROM. ROM is not only slower than RAM, but also it can only be read 8 bits at a time. When copied to RAM, BIOS can be read 16 bits at a time. Remember that POST is a 16 bit program, not 32 bit, and the processor is still in Real mode which means that it cannot execute 32 bit instructions or data transfers.
Next. the Power On Self Test scans for I/O adapters and links the adapter BIOS code into the system BIOS from ROM. It is at this time that you will see the BIOS code for your Adaptec SCSI adapter, for example, loaded. Hardware adpater conflicts may cause hangs during this part of POST. If you see the memory count and other messages on your screen during POST but POST never completes, you probably have an adapter conflict. You can tell that POST has not completed because the computer will not beep. If POST completes, whether successfully or with errors, it always produces one or more beeps.
After the BIOS code for the various I/O adapters has been integrated, the computer’s loadable ABIOS is refreshed, if it has one. Some computers have ABIOS, but many do not. Again, ABIOS is an Advanced BIOS which is capable of supporting a true multitasking operating system.
This normally completes POST and, if there were no errors detected, POST causes the computer to produce one short beep. Of course, if you observe any error messages on the screen, or POST beeps any other beep or combination of beeps, the computer has a hardware problem which should immediately be repaired.
Loading the Bootstrap program
The word “boot” is a short form of the term “bootstrap”. It refers to the fact that computers are really incapable of performing an action of any kind without a program of some sort to help them do it. Computers are so dumb that without some help they cannot even start themselves. To overcome this problem, designers have developed small programs called bootstrap loaders which enable it to “pull itself up by the bootstraps” and become smart enough to find and load the operating system. This bootstrap loader is located on the boot sector of the hard drive.
After POST completes with the “OK” beep, it issues an interruupt 19h to BIOS. BIOS interrup 19h searches for a boot sector on the disks specified in the computer’s boot sequence. Interrupt 19 loads into RAM the first boot sector found in the boot sequence into memory location 7C00h and transfers control of the computer to the bootstrap loader.
If no valid, bootable boot sector is found on any of the disks in the boot sequence, the boot sector contains a little bit of code which displays an error message. If the disk (or diskette) was formatted by OS/2, one of the following messages is presented.
OS/2 !! SYS01475
OS/2 !! SYS02027
or
The file OS2LDR cannot be found. Insert a system diskette and restart the system
If the disk (or diskette) was formatted by DOS, the following message is presented.
Non-System disk or disk error
Replace and strike any key when ready
All of these messages mean exactly the same thing: a valid boot record cannot be found. Refer to “OS/2 !! SYS01475 error message” for more details and how to recover.
If a valid boot block is found, it is loaded into RAM and control of the computer is turned over to it.
OS2BOOT Loads the operating system loader
The OS/2 Boot block finds and loads OS2BOOT. The Boot block is very small – only 16 blocks (sectors) in size. Because of this it is not very smart. One of the issues for the operating system at this time is that the HPFS drivers are not yet loaded, but the Boot block needs to be able to locate the OS2BOOT file on the HPFS volume. To enable this to happen, the Boot block uses a micro HPFS which enables it to locate files in the root directory. The boot block loads the OS2BOOT file.
OS2LDR loads the operating system
The OS2BOOT file and the OS2LDR both use a min-HPFS file system that is larger and more complex than the micro-HPFS file system used by the Boot block which can read the root, \OS2 and \OS2\BOOT directories. The OS2BOOT file loads the OS2LDR file and transfers control of the system to it.
OS2LDR in turn loads OS2KRNL which is the kernel of the operating system. Control is transferred to the OS2KRNL and the first OS/2 logo and copyright message is displayed during kernel initialization. The kernel is still using the mini-HPFS file system.
Processing the CONFIG.SYS file
The OS2KRNL reads the CONFIG.SYS file and begins processing of the statements in a combination sorted and native (unsorted) sequence. The CONFIG.SYS statements are processed in order shown below.
BASEDEV statements in the following order:
SYS
BID
VSD
TSD
ADD
I13
FLT
DMD
At this point, the OS/2 Logo changes to “Loading, please wait…”.
IFS statements are processed. The HPFS file system must be first IFS installed because the first one listed in the CONFIG.SYS file in native order replaces the mini-HPFS.
AUTOCHECK runs HPFS if the dirty file system flag is set.
DEVICE= statements processed.
CALL= statements processed.
RUN= statements processed.
Other statements are processed.
SET variable statements are processed.
All of the device drivers loaded at this time. A Trap error in a device driver can cause system hang at this point.
The program specified by PROTSHELL= statement is started. This is the Graphical Programming Interface which enables OS/2 to support a GUI workplace shell.
STARTUP.CMD and the Workplace Shell are started
The STARTUP.CMD is started if one is present.
If SET AUTOSTART=FOLDERS is specified in the CONFIG.SYS file, then theWorkplace Shell is started. All previously open folders will be opened. Desktop objects are displayed.
If SET AUTOSTART=PROGRAMS is specified in the CONFIG.SYS file, then Program objects which were open at shutdown are restarted.
If SET AUTOSTART=CONNECTIONS is specified, then network objects active at shutdown will be restarted. This may cause the logon prompt to be displayed.
The Boot process is complete
The system is now up and running under user control.