I/O addressing on the 80386 may be performed either by issuing specific I/O instructions to the I/O address space, or issuing general-purpose memory manipulation instructions to memory-mapped I/O.
The I/O address space is separate from the linear physical memory and the I/O instructions do not go through the segmentation or paging hardware. The I/O address space is 64KB in size. It may be mapped in various ways, for instance: 64KB of individually addressable 8-bit ports, 32KB of 16-bit ports, 16KB of 32-bit ports, or any combination of the above up to the maximum allowed 64KB. The processor can transfer 32 bits of data at a time to a device located in the I/O address space, using the IN, OUT, INS, and OUTS commands.
The I/O address space has two protection mechanisms:
The IN, INS, OUT, OUTS, CLI, and STI instructions are only allowed to execute if the CPL (Current Privilege Level in the CS descriptor for the active task) is less than or equal to the value of the IOPL field.
Only system code (privilege level 0) can change the IOPL value.
There is one bit for each 8-bit port in the I/O address space, which means that the I/O permission bit map could be up to 64 kilobits (8KB). If a task references an I/O port and the corresponding bit is on, the processor signals a general protection exception. The exception can then be handled by the system software to initiate an exception handling procedure within the current task, or to initiate a new task, which will redirect the I/O.
By changing bits in the I/O permission bit map of different tasks' TSSs,
an operating system can allocate ports to tasks and avoid having two tasks
use the same port concurrently.