What are IN & OUT instructions in x86 used for?

I've encoutered these to instructions IN & OUT while reading "Understanding Linux Kernel" book. I've looked up reference manual.

5.1.9 I/O Instructions

These instructions move data between the processor’s I/O ports and a register or memory.

IN    Read from a port
OUT   Write to a port
INS/INSB  Input string from port/Input byte string from port 
INS/INSW  Input string from port/Input word string from port 
INS/INSD  Input string from port/Input doubleword string from port
OUTS/OUTSB    Output string to port/Output byte string to port 
OUTS/OUTSW    Output string to port/Output word string to port 
OUTS/OUTSD    Output string to port/Output doubleword string to port

I didn't get few things:

  1. "processor’s I/O ports". What are they? Why would we want to read & write "strings" to & from these ports?
  2. I never encoutered a scenerio where I need to use these instructions. When would I be needing these?
  3. Give some practical examples.

You know how memory addressing works? There's an address bus, a data bus, and some control lines. The CPU puts the address of a byte (or a beginning byte) of memory on the address bus, then raises the READ signal, and some RAM chip hopefully returns the contents of memory at that address by raising or lowering individual lines (corresponding to bits in the byte(s)) on the data bus. This works for both RAM and ROM.

But then there are also I/O devices: Serial and parallel ports, the driver for a PC's tiny internal speaker, disk controllers, sound chips and so on. And those devices also get read from and written to. They also need to be addressed so the CPU accesses the correct device and (usually) the correct data location within a given device.

For some CPU models including the xxx86 series as found in most "modern" PCs, I/O devices share the address space with memory. Both RAM/ROM and IO devices are connected to the same address, data and control lines. For example, the serial port for COM1 is addressed starting at (hex) 03F8. But there's almost certainly memory at the same address.

Here's a really simple diagram:

[https://qph.ec.quoracdn.net/main-qimg-e510d81162f562d8f671d5900da84d68-c?convert_to_webp=true]

Clearly the CPU needs to talk to either memory or the I/O device, never both. To distinguish between the two, one of the control lines called "M/#IO" asserts whether the CPU wants to talk to memory (line=high) or an I/O device (line=low).

The IN instruction reads from an I/O device, OUT writes. When you use the IN or OUT instructions, the M/#IO is not asserted (held low), so memory doesn't respond and the I/O chip does. For the memory-oriented instructions, M/#IO is asserted so CPU talks to the RAM, and IO devices stay out of the communication.

Under certain conditions the IO devices can drive the data lines and the RAM can read them at the same time. And vice versa. It's called DMA.

Traditionally, serial and printer ports, as well as keyboard, mouse, temperature sensors and so forth were I/O devices. Disks were sort of in between; data transfers would be initiated by I/O commands but the disk controller would usually direct-deposit its data in system memory.

In modern operating systems like Windows or Linux, access to I/O ports is hidden away from "normal" user programs, and there are layers of software, privileged instructions and drivers to deal with the hardware. So in this century, most programmers don't deal with those instructions.


Start with something like this:

http://www.cpu-world.com/info/Pinouts/8088.html

You are learning instructions for a very old technology chip/architecture. Back when everything but the processor core was off chip. See the address lines and the data lines and there is a RD read line and WR write line and IO/M line?

There were two types of instructions memory based and I/O based because there were addressable spaces, easily decoded by the IO/M IO or Memory.

Remember you had 74LSxx glue logic, lots of wires and lots of chips to connect a memory to the processor. And memory was just that memory, big expensive chips. If you had a peripheral that needed do do anything useful you also had control registers, the memory might be pixel data, but somewhere you needed to set the horizontal and vertical scan clocks limits, these might be individual 74LSxx latches, NOT memories, having I/O mapped I/O saved on both glue logic and just made a lot of sense from a programmer perspective it also avoided changing your segment registers to aim your 64K memory window around, etc. Memory address space was a sacred resource, esp when you wanted to limit your address decoding to a few bits because every few bits cost you a number of chips and wires.

Like big and little endian memory mapped I/O vs I/O mapped I/O was a religious war. And some of the responses you are going to see to your question are going to reflect the strong opinions that are still around today in the folks that lived it. The reality is that every chip on the market today has multiple busess for various things, you dont hang your real time clock off of the ddr memory bus with an address decoder. Some still even have completely separate instruction and data busses. In a sense Intel won the war for the concept of separate address spaces for different classes of things even though the term I/O port is evil and bad and should not be uttered for say 20-30 more years. You need folks my age that lived it to be retired or gone before the war is truly over. Even the term memory mapped I/O is a thing of the past.

That is really all it ever was, a single address decode bit on the outside of the intel chip that was controlled by the use of specific instructions. Use one set of instructions the bit was on use one set of instructions the bit was off. Want to see something interesting go look at the instruction set for the xmos xcore processors they have lots of things that are instructions instead of memory mapped registers, it takes this I/O mapped I/O thing to a whole new level.

Where it was used is as I described above, you would put things that made sense and you could afford to burn memory address space for like video pixels, network packet memory (maybe), sound card memory (well not that either but you could have), etc. And the control registers, address space relative to the data was very small, maybe only a few registers, were decoded and used in I/O space. the obvious ones are/were serial ports and parallel ports who had little if any storage, you might have had a small fifo on the serial port if anything.

Because address space was scarce it was not uncommon and is still seen today to have memory hidden behind two registers an address register and a data register, this memory is only available through these two registers, it is not memory mapped. so you write the offset into this hidden memory in the address register and you read or write the data register to access the content of the memory. Now because intel had the rep instruction and you could combine it with insb/w outsb/w the hardware decoder would (if you had nice/friendly hardware folks working with you) autoincrement the address whenever you did an I/O cycle. So you could write the starting address in the address register and do a rep outsw and without burning fetch and decode clock cycles in the processor and on the memory bus you could move data pretty fast into or out of the peripheral. This kind of thing is now considered a design flaw thanks to the modern super scalar processors with fetches based on branch prediction, your hardware can experience reads at any time that have nothing to do with executing code, as a result you should NEVER auto increment an address or clear bits in a status register or modify anything as a result of a read to an address. (Editor's note: actually you just make sure your I/O registers with side-effects for read are in uncacheable memory regions/pages. Speculative prefetch of uncacheable memory isn't allowed in the x86 ISA. And can't ever happen for I/O space accesses. But in/out are very slow and partially serializing, and physical memory address space is no longer scarce, so device memory is normally just memory-mapped for efficient access with full-size PCIe transactions.)

The protection mechanisms built into the 386 and on to the present actually make it very easy to access I/O from user space. Depending on what you do for a living, what your company produces, etc. You can most definitely use the in and out family of instructions from user space (application programs in windows and linux, etc) or kernel/driver space, it is your choice. You can also do fun things like take advantage of the virtual machine and use I/O instructions to talk to drivers, but that would probably piss off folks in both the windows and linux worlds, that driver/app wouldnt make it very far. The other posters are correct in that you are likely never going to need to use these instructions unless you are writing drivers, and you are likely never going to write drivers for devices using I/O mapped I/O because you know...the drivers for those legacy devices have already been written. Modern designs most definitely have I/O but it is all memory mapped (from a programmers perspective) and uses memory instructions not I/O instructions. Now the others side if this is DOS is definitely not dead, depending on where you you may be building voting machines or gas pumps or cash registers or a long list of DOS based equipment. In fact if you work somewhere that builds PCs or PC based peripherals or motherboards, DOS based tools are still widely used for testing and for distributing BIOS updates and other similar things. I still run into situations where I have to take code from a current dos test program to write a linux driver. Just like not everyone that can throw or catch a football plays in the NFL, percentage wise very few do software work that involves this kind of stuff. So it is still safe to say these instructions you found are likely not going to be more to you than a history lesson.