Virtual Memory and IO - Part II

Continuing our discussion on VM and IO, this post is about understanding the port IO operation. These port addresses are from a separate address space in x86 devices i.e. they do not use any addresses from the virtual address space, and special IO instructions are used to access them. But in ARM platforms, they happen to share the address space and uses same instruction as memory access. They are about 0x10000 number of IO ports on your intel PC. The mappings of these can be seen in Device Manager in windows, /proc/ioports in Linux.

Example code accessing I/O port is shown below -

uint16_t port_number = 0x45;
uint8_t read_val, write_val = 3;
read_val = inb(port_number);
outb(write_val, port_number);

Example devices that are connected to system via IO ports are serial ports, interrupt controllers, gpio, CMOS and RTC etc. Some port numbers are fixed by the architecture; For example, x86 has the first serial port mapped at 0x3f8 to 0x3ff. Some port have weird use cases, example 0x80 port is usually a Power On Self Test (POST) port and since port I/O takes about 1 microsecond to complete, reading on this port is used to introduce delay in the system. Also there are chances that there could be electrical echo in the IO buses due to recent transaction i.e. a read after a write can return the same data without being successfully written because of echo; writing to 0x80 port is used to flush the bus to avoid this.

Port I/O is slow when compared to 1 CPU cycle and hence is an expensive operation to perform.

Written on March 15, 2020