Additions:
>>**@@[[PikeOs2 Return to Pike Mainpage]]@@**>>
Additions:
PIC
**@@Figure 2: The privilege rings and their use in OS/2@@**
If a process wants to run with a higher privilege than the one it currently has, it must go through a special gate; one might also compare a gate with a tunnel or "wormhole". There are several types of gates such as interrupt, trap, or task gates. The only interesting type for us is the call gate. A call gate allows a one-way transfer of execution from a segment with some privilege to another one with same or higher privilege. The other direction, that is from a "trustworthy" high-privileged code segment to a less trusted lower-privileged segment, is not possible. See figure 2.
PIC
**@@Figure 3: Allowed and forbidden transactions with call gates@@**
Two bits in the processor status register (the IOPL field) determine the level that is necessary to execute I/O CPU instructions. Any code with less than this privilege level will trigger an exception at the first attempt to execute such an instruction. Table 2 lists the affected instructions. Certain instructions will even cause an exception if the process has the privilege to I/O. These instructions require ring 0 privilege. Table 2 also lists these instructions (386 processor).
+----------------------------------------+----------------------------------------+
|Instruction is protected and causes an |Affected instructions |
|exception... | |
+----------------------------------------+----------------------------------------+
|if not in Ring 0 |LIDT, LGDT, LMSW, CLTS, HLT MOV DR*, reg|
| |/ MOV reg, DR* MOV TR*, reg / MOV reg, |
| |TR* MOV CR*, reg / MOV reg, CR* |
+----------------------------------------+----------------------------------------+
|if in Real Mode or in Virtual 8086 Mode |All the above plus LTR, STR, LLDT, SLDT,|
| |LAR, LSL, VERR, VERW ARPL |
+----------------------------------------+----------------------------------------+
|if not at IOPL privilege level or higher|All ring 0 instructions plus OUT, INS, |
|(in Protected Mode) |OUTS, REP INS, REP OUTS STI, CLI |
+----------------------------------------+----------------------------------------+
|if not at IOPL privilege level or higher|All ring 0 and Virtual 8086 Mode |
|(in Virtual 8086 Mode) |instructions plus INT n (Note 1) PUSHF, |
| |POPF, STI, CLI, IRET (Note 2) |
+----------------------------------------+----------------------------------------+
Note 1: INT 3 (opcode 0xcc) and INTO are not affected
Note 2: I/O instructions are enabled or disabled by the I/O permission map in the 386 task state segment
In OS/2, the required privilege level for I/O is ring 2 or better, and tough luck, any user process only runs in ring 3 (figure 2).
In order to get a controlled way to do I/O, the OS/2 developers provided a method to execute 16 bit code at ring 2 level. When the linker produces an executable from several object files, it accepts a special attribute for code segments under certain circumstances. This attribute is named IOPL and is specified in the segment declaration section of a linker definition file (Consult appropriate linker documentation). The linker then annotates the code in a way that every call of a routine in this IOPL segment will be directed through a call gate, rather than a simple call. When such a program is loaded into memory for execution, the loader code in the kernel will generate a R3->R2 call gate for each target called in an IOPL segment (see call gate X in figure 3).
Each time such a call gate is entered, the processor will gain ring 2 privilege and lose it again when leaving by a normal return instruction.
Apparently, this looked like a feature which could be abused, so the IBM developers restricted it in a way that only segments in a DLL can get the IOPL attribute. This appears to be a built-in feature of the program loader, not just the linker, as patching the appropriate tables in the executable will not work.
This restriction is not a bad idea, as it is now no longer possible to make an executable disguising as a normal program, but doing I/O inside. There must be an accompanying DLL, to arouse suspicion - or at least should do so.
This could have been an almost ideal way for moderate I/O - if IBM had provided a similar method for 32 bit applications as well. There is no restriction in the processor itself concerning 32 bit I/O, as one might suspect; it is an intentional limitation. Since IBM will not support 16 bit software any longer in OS/2 for the PowerPC, those unsecure interfaces will disappear in the future.
Nevertheless, you can call routines in such a 16 bit IOPL DLL from a 32 bit executable, and there are several example files floating around in various FTP archives. The key item here is thunking. The main problem with calling code of another size gender is that the program counter as well as the stack pointer needs to be adjusted to the corresponding other size. If address parameters are passed through the stack, these addresses need to be converted as well. This is what a thunking routine does.
Usually the compiler generates such routines automatically when a 16 bit routine is declared, and this is why many high- level programmers do not encounter them at all. However, even if they seem to be invisible, they nevertheless contribute a considerable share to performance degradation if an I/O routine in the IOPL DLL is called from a 32 bit application.