Linux online course

Linux I/O Ports and Hardware Address Ranges

Learn how Linux identifies hardware I/O ports, understand port-mapped I/O and MMIO, inspect /proc/ioports, and troubleshoot resource conflicts.

I/O means input/output communication between the processor, operating system, and physical hardware. A device such as a keyboard controller, serial adapter, storage controller, or display adapter exposes registers that the CPU and its driver use to send commands, read status, and exchange data.

An I/O port, also called an I/O address, is a numbered hardware address or address range used to access those device registers. In this lesson, a port such as 0x3F8 is a hardware address—not a network service endpoint such as TCP port 22.

This topic assumes basic command-line navigation, hexadecimal numbers, CPUs, RAM, device drivers, and Linux virtual filesystems such as procfs. For related command-line fundamentals, see showing the full path of shell commands and the Linux file structure.

What an I/O Port Is

A device register is a small control, status, or data location provided by hardware. A driver reads from and writes to these registers. An I/O port address tells the processor which register location the operation targets.

A device usually owns a range rather than one address. For example, a legacy serial UART might use 0x3F8-0x3FF. The first address can select one register, while subsequent addresses select other UART registers for data, status, configuration, or control.

I/O Address Spaces

Port-mapped I/O

Traditional PC-compatible systems provide a separate port-mapped I/O address space. Special processor instructions access this space instead of ordinary RAM. The operating system reserves ranges in this space and gives drivers permission to use the ranges belonging to their devices.

Port-mapped I/O is the traditional meaning of an I/O port on PC hardware. The address is not a location in normal system memory, even though the CPU uses an address value to select it.

Memory-mapped I/O

Many devices instead use memory-mapped I/O (MMIO). With MMIO, device registers occupy addresses in the physical memory address map. A driver accesses those addresses using memory operations, while the hardware interprets the accesses as register operations rather than RAM reads or writes.

PCI and PCIe devices commonly use MMIO regions described by their PCI BARs. A PCI BAR, or Base Address Register, identifies an assigned I/O or memory resource range for a device.

Hardware and firmware enumerate devices and their required resource ranges. The firmware and Linux kernel then assign resources, make them available to the appropriate drivers, and track ownership. The result may include port-mapped ranges, MMIO ranges, IRQs, and DMA channels.

Allocation, Ownership, and Conflicts

An assigned I/O range normally belongs to one device or driver at a time. Exclusive ownership prevents two unrelated drivers from writing to the same device registers or interpreting the same hardware responses.

A resource conflict occurs when two devices or drivers attempt to claim overlapping ranges, or when a device is configured to use a range already reserved by another device. Such a conflict can cause a driver probe to fail, prevent device initialization, produce unreliable behavior, or make both devices unusable.

Modern Plug and Play firmware and the Linux kernel usually assign resources automatically. Older hardware may have fixed addresses or configurable settings selected by jumpers, switches, firmware options, or driver parameters. Manual changes to legacy settings should be made only with the hardware documentation and driver requirements available.

Viewing Current I/O Assignments with /proc/ioports

/proc/ioports is a kernel-provided procfs file containing I/O port ranges currently reserved by the kernel and device drivers. Display it with:

cat /proc/ioports

Output varies by machine, kernel, firmware, enabled hardware, and drivers. A simplified example might look like this:

0000-001f : dma1
0020-003f : pic1
0060-0064 : i8042
  0060-0060 : i8042
01f0-01f7 : ata_piix
  01f0-01f7 : ata_piix
03f8-03ff : serial

Read each line as a hexadecimal start address, a hexadecimal end address, and an owner label. For example, 03f8-03ff : serial describes the range from 0x3F8 through 0x3FF, inclusive, reserved for a serial subsystem.

Indented lines show a hierarchical relationship. A broad reservation can contain a more specific child reservation, such as a bus, controller, or driver using part of a parent range. Names may refer to bridges, chipsets, PCI or ISA regions, kernel subsystems, or individual drivers.

Filter the listing when investigating familiar device categories:

grep -iE 'serial|ata|ide|vga|keyboard' /proc/ioports

Access to detailed hardware information can depend on system permissions, the kernel configuration, and which drivers are loaded. An empty or limited result does not necessarily mean that no hardware exists.

Common Legacy PC I/O Port Ranges

The following are conventional or historical PC assignments. They are reference points, not guarantees. A modern computer may omit the corresponding device, assign it differently, virtualize it, or use MMIO instead.

Hexadecimal I/O rangeConventional device or functionNotes
0x060-0x064Keyboard controllerCommon legacy keyboard-controller registers; exact subranges and presentation vary.
0x070-0x071CMOS and real-time clockTraditionally used to select and access CMOS/RTC data.
0x1F0-0x1F7 and 0x3F6Primary IDE/ATA controllerLegacy primary ATA command and control registers.
0x170-0x177 and 0x376Secondary IDE/ATA controllerLegacy secondary ATA command and control registers.
0x2F8-0x2FFLegacy serial port COM2Conventional UART range; may be absent or reassigned.
0x378-0x37FLegacy parallel port LPT1Traditional printer/parallel-port range.
0x3B0-0x3DFVGA display adapter registersSeveral VGA-related register ranges are traditionally located here.
0x3E8-0x3EFLegacy serial port COM3Conventional UART range; often absent on current systems.
0x3F8-0x3FFLegacy serial port COM1Common example of a legacy serial UART range.
0x3F0-0x3F7Floppy disk controllerHistorical floppy-controller range; may overlap conventionally listed ranges depending on controller use.

For example, if a system has a legacy COM1-compatible UART, 0x3F8-0x3FF may appear in /proc/ioports. If the system has no legacy serial controller, the range may be absent or represented through a different current driver arrangement.

I/O Ports, IRQs, and DMA

I/O port addresses identify where the CPU reads and writes device registers. They are only one category of hardware resource.

  • I/O port range: identifies register addresses in the port-mapped I/O space.
  • IRQ: an Interrupt Request signal that tells the CPU that a device needs attention, such as when input arrives or an operation completes.
  • DMA: Direct Memory Access, a mechanism that lets a device transfer data to or from RAM with reduced continuous CPU copying.

A device may use one, two, or all three. For example, a controller can expose control registers through I/O ports or MMIO, use an IRQ to report completion, and use DMA to move a large data buffer.

Resource typePurposeTypical Linux inspection sourceExample
I/O port rangeAccess device registers in the port-mapped I/O space./proc/ioports0x3F8-0x3FF for a conventional serial UART.
Memory-mapped I/O rangeAccess device registers placed in the physical memory address map./proc/iomem, lspci -vvA PCIe device's assigned MMIO BAR.
IRQNotify the CPU that a device requires service./proc/interrupts, kernel messagesA controller interrupt after completing a transfer.
DMA channelTransfer data between a device and RAM with less CPU copying.Driver information and kernel messagesA legacy controller's assigned DMA channel.

Investigating Modern Hardware

Legacy ranges are useful for understanding PC hardware, but they do not describe every device in a current Linux system. PCI and PCIe devices commonly use MMIO BARs. Laptops may omit serial, parallel, floppy, and IDE controllers entirely. USB devices are normally discovered through USB host controllers, and virtual machines may present synthetic or virtualized hardware resources.

Use these complementary commands:

cat /proc/iomem
lspci -vv
dmesg | grep -iE 'resource|ioport|conflict'

/proc/iomem shows physical memory address ranges, including regions reserved for MMIO devices. lspci -vv displays PCI devices and detailed assigned resource regions, including BAR information. The dmesg command searches kernel messages for resource reservation, device probing, and conflict reports.

Practical Investigation: A Missing Legacy Range

Suppose you expect to see the conventional COM1 range 0x3F8-0x3FF, but it is not present in /proc/ioports. Several explanations are possible:

  • The machine may not contain a legacy serial controller.
  • The device may use MMIO rather than port-mapped I/O.
  • Firmware or virtualization may expose the device differently.
  • The relevant kernel driver may not be loaded or may not reserve the range in the expected form.

Continue with:

lspci -vv
cat /proc/iomem
dmesg | grep -iE 'resource|ioport|conflict'

These checks distinguish an absent device from a device using MMIO or a different resource representation.

Practical Investigation: A Resource Conflict

If a driver reports that it cannot reserve an I/O region, another driver or device may already own the requested range. A legacy hardware address setting may also overlap a range assigned by firmware or Linux.

  1. Identify the hexadecimal range named in the driver or kernel message.
  2. Search for that range in /proc/ioports.
  3. Read the owner and any indented child entries.
  4. Check kernel messages for the driver that reserved the range.
  5. Compare the result with the hardware configuration and driver documentation before making changes.
cat /proc/ioports
dmesg | grep -iE 'resource|ioport|conflict'

Exam-Relevant Summary

  • An I/O port, or I/O address, is a hardware resource address used to access device registers.
  • Traditional port-mapped I/O uses a separate processor address space; MMIO places device registers in the physical memory address map.
  • /proc/ioports lists I/O port ranges currently reserved by the Linux kernel and drivers.
  • Ranges are normally exclusive because overlapping device register addresses can create resource conflicts.
  • IRQ identifies how a device requests CPU attention; DMA identifies how it can transfer data to or from RAM.
  • Modern PCI and PCIe hardware commonly uses MMIO BARs, so /proc/iomem and lspci -vv complement /proc/ioports.
  • Legacy values such as 0x3F8-0x3FF for COM1 are conventions, not universal assignments.

For broader hardware investigation, combine /proc/ioports, /proc/iomem, lspci -vv, and kernel messages rather than assuming that a familiar legacy range must exist on every system.