last change: Apr 26,2000
OS/2 Aurora KEE32 API
IBM is usually good for hiding easter eggs in every new (seldom enough)
version of OS/2. While, with the OS/2 toolkit 4.5 (available through DEVCON),
they have documented some treasures from older releases, the new WSeB
contains, apparently for JFS, two new APIs, the KEE and the IFSM32.
The KEE is the Kernel Execution Environment, basically the 32 bit
version of what is known as the 16 bit Device Helper API known to every
driver programmer. The following describes this API.
Unfortunately, it is not yet complete enough to allow writing pure 32 bit
physical device drivers, as several device helpers don't have a KEE
equivalent yet (e.g. DevHlp_SetIRQ), and even worse, there is no 32 bit
driver strategy/IDC support yet, so you need at least a 16 bit header and
some small thunk that converts the 16 bit strategy call into a call of
a 32 bit routine in a flat segment of the driver. This is possible and
has already been done. The KEE will supposedly greatly reduce the effort
of writing (almost) 32 bit drivers. Currently, IBM apparently uses KEE
in OS2DASD.DMD and JFS.IFS which are both not exactly PDDs, so won't need
a real strategy entry point at all. See PDD, ADD, and IFS docs how they
actually interface with the rest of the system.
Header and Lib files
To use the API, you need a 32 bit C compiler. Given the calling conventions,
which for basically all functions require CS, DS, ES, and SS to point to
flat kernel segments, it seems to me that finally even EMX/gcc is suitable
for writing the 32 bit part of the driver.
In addition, you need a header file and a
forwarder library. Use the direct save to disk
feature of your browser to get both files - at least the library link may
severely confuse your browser.
The KEE API
KernAllocSpinLock
Synopsis
APIRET APIENTRY KernAllocSpinLock(KEESpinLock* sl);
Description
Initializes a spinlock to synchronize SMP processor access to a resource.
Parameters
- sl
- Pointer to a spinlock structure in 32 bit memory.
KernFreeSpinLock
Synopsis
APIRET APIENTRY KernFreeSpinLock(KEESpinLock* sl);
Description
Destroys a spinlock structure that is no longer in use.
Parameters
- sl
- Pointer to a spinlock structure.
Comments
Actually, this routine is supposed to clear the internal "in-use" flag.
But in 14.039SMP, it does - nothing. I think this is a bug.
KernAcquireSpinLock
Synopsis
VOID APIENTRY KernAcquireSpinLock(KEESpinLock* sl);
Description
Try to acquire the spinlock. If another processor already owns the spinlock,
the caller will busy wait until the other owner releases the lock, then
acquires the lock immediately.
Parameters
- sl
- Pointer to an initialized spinlock structure-
KernReleaseSpinLock
Synopsis
VOID APIENTRY KernReleaseSpinLock(KEESpinLock* sl);
Description
Release the spinlock by the current owner after use.
Parameters
- sl
- Pointer to an acquired spinlock structure.
KernAllocMutexLock
Synopsis
APIRET APIENTRY KernAllocMutexLock(KEEMutexLock* ml);
Description
Initialize a mutexlock. This is basically the semaphore equivalent of
a spinlock. Likewise, it is usable to protect critical regions. The difference
to a spinlock is that waiting on a mutex will send the thread that processor
is executing to sleep. This makes sense - in contrast to a spinlock - for
longer critical regions.
Parameters
- ml
- Pointer to a mutexlock structure in 32 bit memory.
KernFreeMutexLock
Synopsis
APIRET APIENTRY KernFreeMutexLock(KEEMutexLock* ml);
Description
Destroy a mutexlock.
Parameters
- ml
- Pointer to a mutexlock.
Comments
Likewise to KernFreeSpinLock, this is supposed to
do something, but doesn't. Again a sloppiness in code.
KernRequestSharedMutex
Synopsis
VOID APIENTRY KernRequestSharedMutex(KEEMutexLock* ml);
Description
Request a mutex in shared mode. Multiple threads may own the lock.
If a thread already owns the lock, then the calling thread will
block uninteruptibly. The block id is the address of this mutex.
Use KernTryRequestSharedMutex to attempt to acquire the mutexlock without
blocking.
Parameters
- ml
- Pointer to a mutexlock structure.
Comments
KernReleaseSharedMutex
Synopsis
VOID APIENTRY KernReleaseSharedMutex(KEEMutexLock* ml);
Description
Give up an acquired shared mutex.
Parameters
-
-
Comments
KernTryRequestSharedMutex
Synopsis
INT APIENTRY KernTryRequestSharedMutex(KEEMutexLock* ml);
Description
Try to acquire a shared mutexlock. If this fails, 0 is returned, if it
succeeds, the mutexlock is acquired, and 1 is returned.
Parameters
- ml
- Pointer to a mutexlock structure.
KernRequestExclusiveMutex
Synopsis
VOID APIENTRY KernRequestExclusiveMutex(KEEMutexLock* ml);
Description
Request an exclusively owned mutex. Thread will block with the mutexlock
is already owned.
Parameters
- ml
- Pointer to exclusively owned mutexlock structure.
KernReleaseExclusiveMutex
Synopsis
VOID APIENTRY KernReleaseExclusiveMutex(KEEMutexLock* ml);
Description
Give up an owned exclusively locked structure. If there are threads waiting,
they will be unblocked.
Parameters
- ml
- Pointer to an exclusive owned mutexlock structure.
KernTryRequestExclusiveMutex
Synopsis
INT APIENTRY KernTryRequestExclusiveMutex(KEEMutexLock* ml);
Description
Attempt to acquire an exclusive owned mutex lock. Returns 0 if the request
failed, else 1, and the mutexlock is acquired successfully.
Parameters
- ml
- Pointer to an exclusive mutexlock.
KernBlock
Synopsis
APIRET APIENTRY KernBlock(ULONG eventid, ULONG timeout, ULONG flags,
PVOID lockptr, PULONG retdata);
Description
This is an extended version of the DevHlp_ProcBlock function. Basically,
you specify an arbitrary eventid and a timeout. The block may be coordinated
with either an acquired spinlock or a mutexlock, as declared by the flags.
The lock is released immediately before blocking, and reacquired after
returning from the routine, unless the flag bit KEE_BLOCK_NOACQUIRE
prevents re-acquiration. The blocked thread will hang in this routine, and
can be resurrected by a signal (unless turned off with KEE_BLOCK_NOSIGNALS)
or a KernWakeup with the same eventid.
Parameters
- eventid
- Some unique value, which is to be used by KernWakeup to unblock the
thread again.
- timeout
- a timeout value in milliseconds. 0xffffffff is supposedly infinite wait.
- flags
- One or more of the following flags:
- KEE_BLOCK_NOSIGNALS
- Ignore signals, i.e. the block can be released only by end of timeout
or an explicit wakeup.
- KEE_BLOCK_SPINLOCK
- The lockptr points to an acquired KEESpinLock structure.
- KEE_BLOCK_EXMUTEXLOCK
- The lockptr points to an acquired exclusive mutexlock structure.
- KEE_BLOCK_SHMUTEXLOCK
- The lockptr points to an acquired shared mutexlock structure.
- KEE_BLOCK_NOACQUIRE
- Don't reacquire the lock (if lockptr points to a lock at all) when the
KernBlock routine returns.
- lockptr
- Used when one of the three *LOCK bits is set: points to the specified
lock structure
- retdata
- points to a long variable that receives the value passed by the KernWakeup
routine. May be NULL, in this case the value is ignored.
Comments
The KEE_NOSIGNALS bit looks dangerous to me - you can this way easily
produce unkillable processes: Block in an ioctl with this bit set, and a
bug preventing the wakeup, and you won't get rid of this process anymore.
The three *LOCK bits are exclusive since there is only one pointer.
I guess the retdata value us irrelevant for a timeout or an interrupt
by a signal (return values ERROR_TIMEOUT and ERROR_INTERRUPT).
KernWakeup
Synopsis
APIRET APIENTRY KernWakeup(ULONG eventid, ULONG flags, PULONG tcnt, ULONG retdata);
Description
This wakes up threads that are blocking in KernBlock. The eventid to be specified
has to match the eventid used in KernBlock. It is possible to submit a 32 bit
return value to the unblocked thread. The number of threads that are unblocked
is returned.
must match
Parameters
- eventid
- Event id of the blocked thread(s).
- flags
- One or more of the following flag bits:
- KEE_WAKE_SINGLE
- Only wakeup the first matching thread; by default, if multiple threads
are waiting, all will be awaking.
- KEE_WAKE_PRIOINCR
- Run the woke threads with higher priority.
- KEE_WAKE_RETDATA
- return data value specified to the KernBlock retdata variable. By default,
nothing is returned.
- tcnt
- pointer to an ULONG to return the actual number of threads that were woke.
Ignored when NULL.
- retdata
- Data to be returned to the unblocked threads. Ignored when KEE_WAKE_RETDATA
is not set.
Comments
I don't know whether the priority increase issued by KEE_WAKE_PRIOINCR is
permanent, or only for the current timeslice. It shouldn't be permanent.
KernThunkStackTo16
Synopsis
VOID APIENTRY KernThunkStackTo16(VOID);
Description
This will convert a 16:32 SS:ESP value to a 16:16 SS:SP value.
Parameters
None.
Comments
I think this is required for correct calling of 16 bit code from the 32 bit
driver, as 16 bit drivers assume a 16:16 stackpointer.
KernThunkStackTo32
Synopsis
VOID APIENTRY KernThunkStackTo32(VOID);
Description
This will convert a 16:16 SS:SP back to the 16:32 SS:ESP convention.
Parameters
None.
Comments
This is supposedly to be called after returning from 16 bit code.
KernSerialize16BitDD
Synopsis
VOID APIENTRY KernSerialize16BitDD(VOID);
Description
This will acquire a special kernel spinlock.
Parameters
None.
Comments
I think, according to the name, this has to be called before accessing a
16 bit driver. I wonder though, since you supposedly also have to adjust
the stack pointer (KernThunkStackTo16), why both functions haven't been
joined in a single call.
KernUnserialize16BitDD
Synopsis
VOID APIENTRY KernUnserialize16BitDD(VOID);
Description
This releases a special kernel spinlock.
Parameters
None.
Comments
See comments for KernSerialize16BitDD. This apparently needs to be called
after returning from a 16 bit driver.
KernArmHook
Synopsis
VOID APIENTRY KernArmHook(ULONG hook,ULONG data);
Description
This is the 32 bit equivalent of DevHlp_ArmCtxHook.
Parameters
- hook
- Hook as returned from KernAllocateContextHook.
- data
- Data that is passed to the hook when called.
Comments
There is no such thing as a DevHlp_FreeCtxHook. I am unsure whether the
hook handles are portable between 16 and 32 bit code. At least, this
demonstrates that the KEE API has been tailored straight to its use in
JFS and DASD, where one probably never needs to release a hook again.
KernAllocateContextHook
APIRET APIENTRY KernAllocateContextHook(PVOID pfHandler,ULONG dummy,
PULONG pHook);
Synopsis
Description
Allocate a new Context hook for use with KernArmHook.
Parameters
- pfHandler
- This is the address of the hook handler. This is likely a pointer to
a 32 bit function.
- dummy
- I don't know why this is there, it is never accessed in the code.
- pHook
- The pointer to an ULONG where the hook handle is returned.
Comments
See comments for KernArmHook.
KernCopyIn
Synopsis
APIRET APIENTRY KernCopyIn(PVOID trgt, PVOID src, ULONG size);
Description
Copy a buffer of user space data into a kernel buffer.
Parameters
- trgt
- Target buffer address in kernel space.
- src
- Source buffer address in user space.
- size
- number of bytes to copy.
Comments
Finally, the routine I have waited for for eons...
KernCopyOut
Synopsis
APIRET APIENTRY KernCopyOut(PVOID trgt, PVOID src, ULONG size);
Description
Copy a buffer of kernel data into a user space buffer.
Parameters
- trgt
- Target buffer in user space.
- src
- Source buffer in kernel space.
- size
- number of bytes to copy.
KernVMAlloc
Synopsis
APIRET APIENTRY KernVMAlloc(ULONG size, ULONG flags, PVOID* linaddr,
PVOID* physaddr, PSHORT sel);
Description
This is the equivalent of the DevHlp_VMAlloc function.
Parameters
- size
- Number of bytes to allocate.
- flags
- One or more of the following flags. See DevHlp_VMAlloc docs for details.
- KEE_VMA_16MB
- allocate memory from below 16MB
- KEE_VMA_FIXED
- allocate memory that won't be swapped out
- KEE_VMA_SWAP
- allocate memory that is swappable
- KEE_VMA_CONTIG
- allocate contiguous physical memory pages
- KEE_VMA_PHYS
- allocate physical memory (pass address in physaddr argument)
- KEE_VMA_PROCESS
- allocate memory in the process address space.
- KEE_VMA_SGSCONT
- register memory under screen group control
- KEE_VMA_GETSEL
- return a GDT selector for the allocated memory. This option exists also
in DevHlp_VMAlloc (undocumented).
- KEE_VMA_RESERVE
- Don't commit the allocated memory.
- KEE_VMA_SHARED
- allocate memory that is shareable
- KEE_VMA_USEHIGHMEM
- allocate memory from above 16MB.
- linaddr
- address of a variable to receive the linear address of the memory.
- physaddr
- address of a variable that contains the physical address of the memory.
- sel
- address of a variable to receive the allocated GDT selector, when KEE_VMA_GETSEL
is set.
KernVMFree
Synopsis
APIRET APIENTRY KernVMFree(PVOID linaddr);
Description
This frees dynamic memory allocated with KernVMAlloc.
Parameters
- linaddr
- Address of allocated memory.
KernVMLock
Synopsis
APIRET APIENTRY KernVMLock(ULONG flags,PVOID linaddr,ULONG size,
KEEVMLOCK* lock, KEEVMPageList* pglist,
PULONG pgsize);
Description
This is the equivalent of the DevHlp_VMLock function. See the PDD docs for
details.
Parameters
- flags
- One or more of the following bits:
- KEE_VML_NOTBLOCK
- Don't block the call, if the pages can't be locked.
- KEE_VML_CONTIG
- Pages locked must be contiguous.
- KEE_VML_16M
- Pages must be below 16MB.
- KEE_VML_WRITEABLE
- Pages will be writeable.
- KEE_VML_LONGLOCK
- The lock is for long time.
- KEE_VML_VERIFYONLY
- Verify the accessibility of the region. If KEE_VML_WRITEABLE is set, check
for R/W access, else R/O.
- linaddr
- linear address of the memory region.
- size
- Size of the memory region.
- lock
- Pointer to a lock data structure that contains the lock information.
- pglist
- Pointer to a pagelist structure, provided by the user
- pgsize
- Pointer to an ULONG where the size of the pagelist structure is
returned.
KernVMUnlock
Synopsis
APIRET APIENTRY KernVMUnlock(KEEVMLOCK* lock);
Description
Unlock a memory region.
Parameters
- lock
- Pointer to the lock structure used by KernVMLock.
KernLinToPageList
Synopsis
APIRET APIENTRY KernLinToPageList(PVOID linaddr,ULONG size,KEEVMPageList* list,PULONG pgsize);
Description
Convert a linear address region to a pagelist. This is the equivalent to
DevHlp_LinToPageList.
Parameters
- linaddr
- Address of the linear region
- size
- Length of the linear region
- list
- Address of an array of pagelist elements long enough to receive the
pagelist entries.
- pgsize>
- Pointer to an ULONG that contains the number of pagelist entries
that were actually stored.
KernVMSetMem
Synopsis
APIRET APIENTRY KernVMSetMem(ULONG flags, PVOID linaddr, ULONG size);
Description
This is the equivalent of the DevHlp_VMSetMem function.
Parameters
- flags
- One or more of the following flags:
- KEE_VMS_UNCOMMIT
- Uncommit the region
- KEE_VMS_RESIDENT
- make the region resident
- KEE_VMS_SWAPPABLE
- make the region swappable
- linaddr
- Linear address of region
- size
- Size of region
KernSelToFlat
Synopsis
ULONG KernSelToFlat(ULONG addr16);
Description
Convert a 16:16 address to a flat address. Returns the linear flat address.
Parameters
- addr16
- 16:16 pointer
KernDynamicAPI
Synopsis
APIRET APIENTRY KernDynamicAPI(PVOID addr, ULONG cnt, ULONG dummy, PUSHORT sel);
Description
This is the equivalent of the DevHlp_DynamicAPI function.
Parameters
- addr
- Address of the routine to be called through this gate.
- cnt
- Number of arguments to be copied from user stack to kernel stack
- dummy
- I don't know what this parameter is for. It is not used in the code.
- sel
- Pointer to a variable where the generated GDT gate selector is returned
KernRASSysTrace
Synopsis
APIRET APIENTRY KernRASSysTrace(ULONG major,ULONG minor,PVOID buf, ULONG size);
Description
This is the equivalence of the DevHlp_RASTrace function.
Parameters
- major
- Major number of RAS event
- minor
- Minor number of RAS event
- buf
- buffer to be added to the RAS log
- size
- size of the buffer
Comments
This is not explained in the PDD reference manual, but in the debug handbook
IIRC.
KernPerfSysTrace
Synopsis
APIRET APIENTRY KernPerfSysTrace(ULONG major,ULONG minor,PVOID buf, ULONG size);
Description
This is the equivalent of the DevHlp_Perftrace function used by PerfView.
Parameters
- major
- Major number of Perf event
- minor
- Minor number of Perf event
- buf
- buffer to be added to the Perf log
- size
- size of the buffer
KernLockFile
Synopsis
APIRET APIENTRY KernLockFile(HFILE hfd,KEEhfile* khfd);
Description
This function converts a user space file handle to a system file table
pointer.
Parameters
- hfd
- User space file handle
- khfd
- Pointer to an variable to return the SFT entry pointer.
Comments
This is some sort of DosOpen to access user files. This seems to be a kludge
required for some feature of JFS.
KernUnLockFile
Synopsis
APIRET APIENTRY KernUnLockFile(KEEhfile khfd);
Description
This will return the specified SFT pointer to the system.
Parameters
- khfd
- SFT pointer.
Comments
This is some sort of DosClose after a file has been opened with KernLockFile.
KernGetFileSize
Synopsis
APIRET APIENTRY KernGetFileSize(KEEhfile khfd,KEEfilesize* sz);
Description
This returns the size of the file designated by KernLockFile.
Parameters
- khfd
- SFT pointer
- Address of a double long variable to hold the size of the file.
-
Comments
Like the other SFT related functions, this seems to be a hack for JFS.
KernTestFileCache
Synopsis
APIRET APIENTRY KernTestFileCache(KEEhfile khfd);
Description
Check whether the associated IFS for the specified file allows access to
the file cache. Return 1 if yes, 0 if not. This seems to be again a special
feature for JFS.
Parameters
- khfd
- SFT pointer
KernReadFileAt
APIRET APIENTRY KernReadFileAt(KEEhfile khfd,PVOID buf, QWORD off,
ULONG nbytes, PULONG nread);
Synopsis
Description
This reads the content of a file into a buffer.
Parameters
- khfd
- SFT pointer
- buf
- buffer to read data into
- off
- Offset in file to start reading
- nbytes
- Number of bytes to read
- nread
- Pointer to an ULONG to receive the number of bytes actually read.
Comments
KernReadFileAtCache
APIRET APIENTRY KernReadFileAtCache(KEEhfile khfd,KEECachePages** ptr,
QWORD off, ULONG nbytes, PULONG nread);
Synopsis
Description
This seems to do the same as KernReadAtFile, but reads from the cache and
returns the corresponding pages of the cache data structure.
Parameters
- khfd
- SFT pointer
- ptr
- Pointer to a variable the receives the cache data structure for the
specified data blocks.
- off
- Offset in file to start reading
- nbytes
- Number of bytes to read
- nread
- Pointer to an ULONG to receive the number of bytes actually read.
Comments
Yet another JFS hack. Meanwhile I understand why IBM is reluctant to
provide JFS support for Warp 4.
KernReturnFileCache
Synopsis
APIRET APIENTRY KernReturnFileCache(KEEhfile khfd,KEECachePages* ptr);
Description
This appears to be the "free" function to return the ptr structure from
KernReadFileAtCache back to the system.
Parameters
- khfd
- SFT pointer
- ptr
- Pointer to a previously received cache data structure.
KernCreateUconvObject
Synopsis
APIRET APIENTRY KernCreateUconvObject(USHORT codepage, KEEUnicodeStruct* ucs);
Description
This initializes a data structure related to Unicode conversion.
Parameters
- codepage
- Codepage for the data structure.
- ucs
- Pointer to the unicode conversion structure created.
Comments
Finally, this seems to be Unicode support in the kernel...
KernStrFromUcs
Synopsis
APIRET APIENTRY KernStrFromUcs(KEEUnicodeStruct* ucs, PCHAR trgt,
PCHAR usrc, ULONG trgtsize, ULONG srcsize);
Description
This converts a string from Unicode to ASCII.
Parameters
- ucs
- Pointer to the Unicode conversion object created with KernCreateUconvObject.
- trgt
- Pointer to the ASCII buffer
- usrc
- Pointer to the Unicode buffer
- trgtsize
- length of the target buffer
- srcsize
- length of the source buffer
KernStrToUcs
Synopsis
APIRET APIENTRY KernStrToUcs(KEEUnicodeStruct* ucs, PCHAR utrgt, PCHAR src,
ULONG trgtsize,ULONG srcsize);
Description
This converts a string from ASCII to Unicode.
Parameters
- ucs
- Pointer to the Unicode conversion object created with KernCreateUconvObject.
- utrgt
- Pointer to the Unicode buffer
- src
- Pointer to the ASCII buffer
- trgtsize
- length of the target buffer
- srcsize
- length of the source buffer