I/Oアドレスの情報を表示する|/proc/ioports と lspci -vv で確認する現代Linuxの実務

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Linuxtips, デバイス管理 > I/Oアドレスの情報を表示する|/proc/ioports と lspci -vv で確認する現代Linuxの実務

この記事のポイント

・/proc/ioports ファイルを参照すれば、現在使われているI/Oアドレスの情報を一覧で表示できる
・PCIデバイス単位で詳細を確認するなら lspci コマンド(特に lspci -vv)が現実的
・現代のLinux(RHEL9・Ubuntu 24.04系)でも /proc/ioports と lspci はそのまま使える
・lsusb / dmesg / journalctl と組み合わせると、デバイス認識トラブルの一次切り分けが速くなる

Linuxシステムでは、入出力デバイスに予約されたCPUのメモリマップを表示出来ます。 情報を表示するには/proc/ioportsファイルを参照します。 参照する場合は、moreやlessコマンドを使用すると良いでしょう。 ■PCIデバイスの情報を表示する ------------------------------------------------------------------------------ $ more /proc/ioports   ←I/Oアドレス情報を表示します。 0000-0cf7 : PCI Bus 0000:00 0000-001f : dma1 0020-0021 : pic1 0040-0043 : timer0 0050-0053 : timer1 0060-0060 : keyboard 0064-0064 : keyboard 0070-0071 : rtc0 0080-008f : dma page reg 00a0-00a1 : pic2 00c0-00df : dma2 (中略) 0d00-feff : PCI Bus 0000:00 1000-103f : 0000:00:07.3 1000-103f : pnp 00:01 1000-1003 : ACPI PM1a_EVT_BLK 1004-1005 : ACPI PM1a_CNT_BLK 1008-100b : ACPI PM_TMR 100c-100f : ACPI GPE0_BLK 1010-1015 : ACPI CPU throttle 1040-104f : 0000:00:07.3 1040-104f : pnp 00:01 1060-107f : pnp 00:0d 1080-10bf : 0000:00:07.7 10c0-10cf : 0000:00:07.1 --続ける--(0%)    ←スペースキーを押すと次ページが表示されます。 ------------------------------------------------------------------------------
「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

I/Oアドレスとは何か:CPUと周辺デバイスをつなぐ「番地」

I/Oアドレス(I/Oポートアドレス)は、CPUが周辺デバイス(キーボード、シリアルポート、ネットワークカードなど)とデータをやり取りするための「番地」のような番号です。歴史的には x86アーキテクチャに特有の概念で、CPUが in/out 命令でこのアドレスにアクセスすると、対応するデバイスに直接コマンドが届く仕組みになっています。 たとえばキーボードコントローラーは古典的に 0x60 と 0x64、PICは 0x20/0x21 と 0xA0/0xA1、シリアルポートCOM1は 0x3F8~0x3FF が割り当てられてきました。Linuxカーネルはこれらの割り当て情報を /proc/ioports という仮想ファイルに集約していて、root権限なしで自由に参照できます。 現代のサーバーでは仮想化/PCIeネイティブが主流になり、レガシーI/Oポートを直接叩く場面はほぼなくなりました。しかし「どのデバイスがどの範囲を確保しているか」を一覧する用途では、今でも /proc/ioports が最短ルートです。

/proc/ioportsファイルの読み方:階層構造とインデント

/proc/ioports の出力は16進数の範囲(開始-終了)とその所有者(デバイス名やバス名)が2列で並んでいます。インデントは「親→子」の階層関係を表していて、外側のPCIバスの範囲内に各デバイスがぶら下がる入れ子構造で表示されます。 [user@host ~]$ cat /proc/ioports | head -20 0000-0cf7 : PCI Bus 0000:00 0000-001f : dma1 0020-0021 : pic1 0040-0043 : timer0 0060-0060 : keyboard 0064-0064 : keyboard 0070-0071 : rtc0 00f0-00ff : fpu 0170-0177 : 0000:00:01.1 0170-0177 : ata_piix 01f0-01f7 : 0000:00:01.1 01f0-01f7 : ata_piix ハイフン区切りの16進数が割り当てられたアドレス範囲、コロン以降がそのアドレスを使っているドライバ名です。0000:00:01.1 のようなハイフン区切りなしのID表記は「ドメイン:バス:デバイス.ファンクション」というPCIアドレスで、lspci の出力と一対一で対応します。

lspciコマンドでPCIデバイスを一覧表示する

I/Oアドレスを「デバイス単位」で見たいときは lspci コマンドが最も実用的です。引数なしの lspci でも要点が一覧で出ます。 [user@host ~]$ lspci 00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02) 00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II] 00:01.1 IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01) 00:02.0 VGA compatible controller: Cirrus Logic GD 5446 00:03.0 Ethernet controller: Intel Corporation 82540EM Gigabit Ethernet Controller (rev 02) 00:07.0 ISA bridge: Intel Corporation 82371AB/EB/MB PIIX4 ISA (rev 08) 左端の 00:01.1 が「ドメイン:バス:デバイス.ファンクション」、その右がデバイスクラスと製品名です。/proc/ioports の入れ子表示と lspci の一覧表示を見比べると、どのドライバがどのI/Oアドレスを使っているかを一目で対応付けできます。

lspci -vvで割り当て済みI/Oアドレスの詳細を確認する

lspci に -vv(verbose 2回)を付けると、デバイスごとに「I/O ports」「Memory」「IRQ」など、リソースの割り当て状況が詳細に表示されます。 [user@host ~]$ sudo lspci -vv -s 00:01.1 00:01.1 IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01) Subsystem: Red Hat, Inc. Qemu virtual machine Physical Slot: 1 Flags: bus master, medium devsel, latency 0 I/O ports at 01f0 [size=8] I/O ports at 03f4 [size=1] I/O ports at 0170 [size=8] I/O ports at 0374 [size=1] I/O ports at c000 [size=16] Kernel driver in use: ata_piix Kernel modules: ata_piix I/O ports at 01f0 [size=8] のような行が見えれば、そのデバイスが 0x01F0 から8バイト分を確保していることを意味します。/proc/ioports 側の表示(01f0-01f7 : ata_piix)と完全に一致するはずです。-vv は情報量が多く、PCIデバイスの状態確認には欠かせないオプションです。

lsusb / dmesg / journalctlでI/O周辺の認識状況を確認する

I/OアドレスはPCIに加えてUSBデバイスやレガシーポートにも関係します。USBの認識状況は lsusb、起動時のデバイス検出ログは dmesg または journalctl で見ます。 [user@host ~]$ lsusb Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 001 Device 002: ID 0627:0001 Adomax Technology Co., Ltd Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub [user@host ~]$ dmesg | grep -i ioport [ 0.123456] PCI: Using configuration type 1 for base access [ 0.234567] ioport_resource: 0000:00:01.1 reg 0x10: [io 0x01f0-0x01f7] dmesg は起動直後のリングバッファ、journalctl -k はsystemd時代の永続ログです。「デバイスを挿したのに認識されない」「I/Oアドレス競合の警告が出ている」といったトラブルでは、まずここを見ると一次切り分けがほぼ終わります。

I/OアドレスとメモリマップドI/O(MMIO)の違い

x86の世界には「I/Oポート空間(in/out命令で叩く)」と「メモリマップドI/O(通常のメモリアクセス命令で叩く)」の2つがあります。/proc/ioports が示すのは前者、後者は /proc/iomem で参照します。 [user@host ~]$ cat /proc/iomem | head -10 00000000-00000fff : Reserved 00001000-0009fbff : System RAM 00100000-bffd9fff : System RAM fec00000-fec003ff : IOAPIC 0 fee00000-fee00fff : Local APIC fffc0000-ffffffff : Reserved 現代のPCIeデバイスはほぼMMIOで動作するため、グラフィックボードやNVMeのリソースは /proc/iomem 側に表示されます。古典的なI/Oポートを確認したいなら /proc/ioports、グラフィックや高速I/Oなど現代的なリソースを見たいなら /proc/iomem を使い分けます。

シェルから絞り込み表示する:grep・awkとの組み合わせ

/proc/ioports は単純な2列テキストなので、grepやawkで簡単に絞り込めます。 [user@host ~]$ grep -i serial /proc/ioports 03f8-03ff : serial 02f8-02ff : serial [user@host ~]$ awk '{print $1}' /proc/ioports | head -5 0000-0cf7 0000-001f 0020-0021 0040-0043 0060-0060 シリアルポートの割り当て、NIC(Ethernet)のI/Oアドレス、特定範囲(0xC000~)の使用状況など、目的別に必要な行だけを抜き出せるので、スクリプト化に向きます。

【重要】I/Oアドレスを確認する時の注意点

I/Oアドレスを表示する作業自体は危険性のない参照操作ですが、いくつか注意点があります。 1つ目は「root権限なしでも /proc/ioports は読めるが、lspci -vv の詳細情報は root が必要な項目がある」点です。一般ユーザーで lspci -vv を実行すると、レジスタの中身など一部が ! でマスクされて表示されません。完全な情報が欲しいときはsudoを付けます。 2つ目は「I/Oアドレスは仮想マシン(KVM/VMware/Hyper-V)とベアメタルで内容が大きく異なる」点です。仮想マシンでは仮想化されたI/Oポートが /proc/ioports に並びます。物理マシンのトラブルシューティングで参照する場合は、必ず物理ホスト側で確認します。 3つ目は「現代の高速デバイス(NVMe・GPU・10GbE NICなど)はI/Oポートをほとんど使わずMMIOで動く」点です。/proc/ioports に出てこなくても異常ではありません。MMIO側のリソースは /proc/iomem または lspci -vv の Memory at ... 行で確認します。 4つ目は「/proc/ioports の値を変更することはできない」点です。これは読み取り専用の仮想ファイルで、cat した結果も瞬間値のスナップショットです。デバイスのI/Oアドレスを変更したい場合はBIOSやUEFIの設定、もしくはカーネルパラメータで指定する必要があります。

「Permission denied」や lspci 未インストール時の対処

ディストリビューションによっては lspci が標準でインストールされていない場合があります。RHEL系では pciutils、Debian系でも pciutils パッケージに含まれています。 [root@host ~]# dnf install pciutils ←RHEL系 [root@host ~]# apt install pciutils ←Debian系 また、コンテナ(Docker等)の中から /proc/ioports を見ると、ホストの情報がそのまま見えるケースとPID名前空間で制限されるケースが混在します。コンテナ環境でI/Oアドレスを確認したいときは、必ずホスト側のシェルで実行するのが安全です。 最後に、SELinuxやAppArmorがenforcingで動いている環境で sudo lspci -vv を叩くと、まれにaudit.logにdeny記録が残ることがあります。これは情報取得自体は成功するものの、ポリシー上「念のため記録」されるケースで、機能には影響しません。気になる場合は audit2allow で確認します。

本記事のまとめ:I/Oアドレス情報を表示するコマンド早見表

最後に、I/Oアドレス周辺の情報を表示するコマンドを一覧にまとめます。
目的 コマンド例
I/Oアドレスを範囲一覧で表示 cat /proc/ioports(または more / less
PCIデバイスを一覧表示 lspci
デバイス別のI/Oアドレス/メモリ詳細 sudo lspci -vv -s バス:デバイス.ファンクション
USBデバイスの認識状況 lsusb
MMIO(メモリマップドI/O)の割り当て確認 cat /proc/iomem
起動時のデバイス検出ログ dmesg / journalctl -k
シリアルポートのI/Oアドレス抽出 grep -i serial /proc/ioports
I/Oアドレスの情報を表示する基本は /proc/ioports の参照ですが、現代のLinuxサーバーでは lspci -vv とセットで使うのが実用的です。デバイスが認識されない/IRQが衝突しているような疑いがあるときは、/proc/ioports → lspci -vv → dmesg の順に追うと、原因切り分けが最短で進みます。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。