What are the IN & OUT instructions for x86?

I included them in the IN and OUT instructions while reading the book Understanding Linux Kernel. I was looking for a reference guide.

5.1.9 I / O instructions

These instructions move data between processor 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 did not get a few things:

  • "I / O Port Processors". Who are they? Why do we want to read and write "lines" to and from these ports?
  • I have never used scenerio where I need to use these instructions. When will I need it?
  • Give some practical examples.
+41
assembly x86 linux-kernel
Jul 09 '10 at 19:23
source share
7 answers

Do you know how memory addressing works? There is an address bus, a data bus and some control lines. The CPU puts the address of the byte (or start byte) of the memory on the address bus, then raises the READ signal, and some RAM chip, I hope, returns the contents of the memory to this address by raising or lowering individual lines (corresponding to bits in bytes (bytes)) on the data bus . This works for both RAM and ROM.

But then there are also I / O devices: serial and parallel ports, a driver for the tiny internal PC speaker, disk controllers, sound chips, etc. And these devices are also read and written. They must also be addressed so that the processor accesses the correct device and (usually) the correct location of the data on this device.

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

Here's a really simple diagram:

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

Obviously, the CPU needs to talk either with memory, or with an I / O device, neither one nor the other. To distinguish them, one of the control lines, called "M / # IO," states whether the processor wants to speak with memory (line = high) or an I / O device (line = low).

An IN instruction is read from an I / O device, an OUT record. When you use the IN or OUT instructions, M / # IO is not declared (kept low), so the memory does not respond and the I / O chip does this. For memory-oriented instructions, the M / # IO asserts that the processor is talking to RAM and the I / O devices are out of communication.

Under certain conditions, IO devices can control data lines, and RAM can read them simultaneously. And vice versa. It is called DMA.

Traditionally, serial and printer ports, as well as keyboards, mice, temperature sensors, etc. were input / output devices. The disks were among themselves; data transfer will be initiated by I / O commands, but the disk controller will usually direct its data to system memory.

In modern operating systems, such as Windows or Linux, I / O ports are hidden from “normal” user programs, and there are software layers, privileged instructions, and drivers for processing the hardware. Therefore, in this century, most programmers do not cope with these instructions.

+60
Jul 09 '10 at 19:34
source share

Start with something like this:

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

You are learning the instructions for a very old technology chip / architecture. Back when everything except the processor core was disconnected from the chip. See Address Lines and Data Lines, and is there an RD read line and a WR write line and an I / O line?

There are two types of memory and I / O instructions, since there are addressable spaces that are easily decoded by IO / M IO or memory.

Remember that you had 74LSxx glue logic, lots of wires, and lots of chips to connect memory to the processor. And the memory was exactly that memory, big expensive chips. If you have a peripheral device that needs to be done, something useful, you also have control registers, then the memory may be pixel data, but somewhere you had to set the horizontal and vertical intervals of the scanning hours, these could be separate shutters 74LSxx, NOT memories that have I / O stored on both glue logics and just matter a lot from a programmer’s point of view, he also avoided changing segment registers to target your 64K memory window, etc. The memory address space was a sacred resource, for example, when you wanted to limit the decoding of an address to a few bits, because each bit of a bit cost you several chips and wires.

Like a large and small memory card with an I / O index, I / O versus I / O I / O was a religious war. And some of the answers that you are going to look at your question will reflect the strong opinions that still exist today among the people who lived it. The reality is that every chip on the market today has several busess for different things, you do not hang your real-time clock from the ddr memory bus with an address decoder. Some still even have separate buses with instructions and data. In a way, Intel won the war for the concept of separate address spaces for different classes of things, although the term I / O port was evil and bad and should not be spoken in 20-30 years. You need people of my age who lived in order to be fired or to leave before the war really ended. Even the term memory represented by I / O is a thing of the past.

This is really all there has ever been, a single address decoding bit on the outside of an Intel chip, which was controlled using specific instructions. Use one set of instructions in which the bit was used, using one set of instructions, the bit was turned off. Want to see something interesting, look at the instruction set for xmos xcore processors, they have a lot of things that are instructions, not memory, stored in memory, and takes this I / O information to I / O to a new level.

Where it was used, as I said above, you would put everything that made sense, and you could allow yourself to write down the address space for memory, for example, for video elements, network packet memory (possibly), sound card memory (well, you could have) etc. And the control registers, the address space relative to the data was very small, maybe just a few registers were decoded and used in the I / O space. obvious / were serial ports and parallel ports that didn't have much storage, maybe you had a small fifo on the serial port.

Since the address space was scarce, it was not uncommon, and today there is still memory hidden behind two registers, an address register and a data register, this memory is accessible only through these two registers, it is not displayed in memory. therefore, you write the offset to this hidden memory in the address register, and you read or write the data register to access the contents of the memory. Now, since Intel had a rep statement, and you could combine it with insb / w outsb / w, a hardware decoder (if you had nice / friendly hardware people working with you), address auto-increment every time you did I / O cycle. Thus, you can write the starting address in the address register and rep outsw without writing fetch and decoding clock cycles in the processor, and on the memory bus you can quickly move data to or from peripherals. This type of thing is now considered a design flaw due to modern superscalar processors with branch prediction-based samples, your equipment can read data at any time that has nothing to do with code execution, as a result, you NEVER automatically increase the address or clear the bit in status register or change anything as a result of reading the address.

The security mechanisms built into 386 and currently actually facilitate I / O access from user space. Depending on what you do for a living, what your company produces, etc. You can definitely use the family of instructions from user space inside and outside (application programs in windows and linux, etc.) Or the kernel / driver space, this is your choice. You can also do funny things, for example, use a virtual machine and use I / O instructions to communicate with drivers, but this will probably cause people in both the Windows and Linux worlds that the driver / application will not do this very far. Other posters are correct in that you most likely will not need to use these instructions unless you write drivers, and you probably will never write drivers for devices that use I / O, as you know. The drivers for these legacy devices are already written. Modern designs definitely have I / O, but they all appear in memory (from the point of view of programmers) and use memory instructions rather than I / O instructions. Now the other side, if it's DOS, is definitely not dead, depending on where you can build voting machines or gas pumps or cash registers or a long list of DOS-based equipment. In fact, if you work somewhere who builds PCs or PC-based peripherals or motherboards, DOS-based tools are still widely used to test and distribute BIOS updates and other similar things. I still encounter situations where I need to take the code from the current dos test program in order to write the linux driver. Just like not everyone who can throw or catch football matches in the NFL, there is a very small percentage of the software work that includes such things. Thus, it is safe to say that these instructions that you found will most likely not be more important to you than a history lesson.

+22
Jul 11 2018-10-11T00:
source share

Give some practical examples.

First find out how:

  • create a minimal bootloader OS and run it on QEMU and real hardware, as I explained here: https://stackoverflow.com/a/212829/
  • make some BIOS calls to perform quick and dirty I / O

Then:

  • PS / 2 controller : get the scancode ID of the last character entered on the keyboard in al :

     in $0x60, %al 

    Minimal example

  • Real-time clock (RTC) : get the time on the wall with the definition of seconds:

     .equ RTCaddress, 0x70 .equ RTCdata, 0x71 /* al contains seconds. */ mov $0, %al out %al, $RTCaddress in $RTCdata, %al /* al contains minutes. */ mov $0x02, %al out %al, $RTCaddress in $RTCdata, %al /* al contains hour. */ mov $0x04, %al out %al, $RTCaddress 

    Minimal example

  • Programmable Timer Interval (PIT) : generate one number of interrupts 8 every 0x1234 / 1193181 seconds:

     mov $0b00110100, %al outb %al, $0x43 mov $0xFF, %al out %al, $0x34 out %al, $0x12 

    Minimal example

    A Using the Linux kernel 4.2 . There are others.

Tested: QEMU 2.0.0 Ubuntu 14.04 and real Lenovo ThinkPad T400 hardware.

How to find port numbers: Is there an x86 I / O port assignment specification?

https://github.com/torvalds/linux/blob/v4.2/arch/x86/kernel/setup.c#L646 contains a list of ports used by the Linux kernel.

Other architectures

Not all architectures have such IO instructions.

In ARM, for example, IO is performed simply by writing specific memory addresses to magic hardware.

I think that this is what https://stackoverflow.com/a/2129346/... means "memory-mapped I / O and I / O."

From a programmer’s point of view, I prefer the ARM path, since IO instructions already need magic addresses to work, and we have huge unused address spaces in 64-bit addressing.

See https://stackoverflow.com/a/2128778 for a specific ARM example.

+7
Oct 30 '15 at 20:18
source share

If you are not writing an operating system, you will never use these instructions.

X86-based machines have two independent address spaces - the memory address space that you are familiar with, and then the I / O address space. The I / O port addresses are only 16 bits wide, and the reference low-level registers and other low-level widgets that are part of the I / O device are something like a serial or parallel port, a disk controller, etc.

There are no practical examples, since they are used only by device drivers and operating systems.

+3
Jul 09 '10 at 19:37
source share

At the hardware level, most microprocessors have little or no I / O capability. Several processors have one or more contacts that can be turned on and off using special instructions and / or one or more contacts that can be tested using special instructions for branching, but such functions are rare. Instead, I / O operations are usually handled by connecting the system, so accessing the range of memory addresses will have some effect, or by including "in" and "out" commands that behave like load / store memory operations, except that special the signal “This is an I / O operation instead of a memory operation” is displayed. In the days of 16-bit processors, there used to be some real advantages with respect to specialized I / O instructions. These benefits are pretty much controversial right now, because you can simply allocate a large chunk of one address space for I / O and still have plenty of memory remaining.

Since the program can cause significant damage to the system by inadequately following I / O instructions (for example, such instructions can perform arbitrary disk accesses), all modern operating systems prohibit the use of such instructions in user level code. Some systems may allow the virtualization of such instructions; if the user code is trying to write to the input / output ports 0x3D4 and 0x3D5, for example, the operating system may interpret this as an attempt to set some video control control registers to move the blinking cursor. Each time a user program executes an OUT command, the operating system would capture, depending on what the user program was trying to do, and act accordingly.

In the vast majority of cases, even if the operating system translates the IN or OUT instruction to something suitable, it would be more efficient to request the appropriate actions directly from the operating system.

+3
Jul 09 '10 at 20:28
source share

There is a bit more cheating for this. It does not just multiplex a separate 64 KB address space onto the same wires as the "additional bus address / chip." Intel 8086 and 8088 and their clones also multiplex the data bus and address bus; all very unusual things in processors. The data tables are filled with the minimum / maximum configuration information and all the latch registers that must be connected to it in order to make it behave “normally”. On the other hand, it saves the load and the gate and the “or” gate in address decoding, and 64kb should be “sufficient for I / O ports”: P.

In addition, for all those who are engaged only in driver developers, please note: in addition to people using Intel-compatible chips on other equipment, and not just on PCs (they were never intended to be used on IBM PCs in the first place - IBM just I took it because they were cheap and already on the market), Intel also sells microcontrollers with the same set of instructions (Intel Quark), and there are many "systems on a chip" from other suppliers with the same set of instructions. I do not think that you will be able to pick everything up, with a separate "user core" and "drivers" in 32kb :). For most things, such complex "operating systems" are neither optimal nor desirable. By forming some UDP packets in RAM, and then putting them in some ring buffer and making some relays, click-to-click does not require a 30 MB kernel and load time of 10 seconds, you know. This is basically the best choice if the PIC microcontroller is not enough, but you do not need an entire industrial PC. Therefore, port I / O instructions are very often used, and not only by driver developers for larger operating systems.

+1
Apr 27 '17 at 13:07 on
source share

The CPU is connected to some external controllers via io ports. on an old x86 computer, I work with a floppy disk using I / O ports. , , .

. , ( ) .

/ http://webster.cs.ucr.edu/AoA/DOS/ch03/CH03-6.html#HEADING6-1

0
09 . '10 19:36
source share



All Articles