13
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PCI ボードをデバイスドライバを用いずに python から操作する

Posted at

これは何か

PCI ボードをデバイスドライバに頼らず python を使って操作してみます。

環境、必要なもの

背景知識

手順

1. 機器の情報を収集する

lspci を使って、設定ヘッダの情報を確認

$ lspci -v -nn
...
...
05:0c.0 Unassigned class [ff00]: Interface Corp Device [1147:0c5d] (rev 03)
	Subsystem: Interface Corp Device [1147:0001]
	Flags: slow devsel, IRQ 19
	I/O ports at 2000 [size=32]
	I/O ports at 2048 [size=4]

05:0d.0 Unassigned class [ff00]: Interface Corp Device [1147:0c8e] (rev 01)
	Subsystem: Interface Corp Device [1147:2090]
	Flags: slow devsel, IRQ 16
	Memory at 90502000 (32-bit, non-prefetchable) [size=64]
	Memory at 90501000 (32-bit, non-prefetchable) [size=64]
	Memory at 90503000 (32-bit, non-prefetchable) [size=32]
...
...
  • オプション

    • -v : 通信方式、アドレス、を含む詳細を表示
    • -nn : ベンダ ID、装置 ID と共に、名称も表示
  • 見方

    • 05:0c.0 に接続された Interface Corp (ID 0x1147) の装置 ID 0x0c5d です
      • 2 つの PCI I/O port を持っています
        • アドレス 0x2000 から 32 byte
        • アドレス 0x2048 から 4 byte
    • 05:0d.0 に接続された Interface Corp (ID 0x1147) の装置 ID 0x0c8e です
      • 3 つの PCI Memory port を持っています
        • アドレス 0x90502000 から 64 byte
        • アドレス 0x90501000 から 64 byte
        • アドレス 0x90503000 から 32 byte

2. PCI I/O port へ接続する

$ sudo ipython

PCI I/O port へのアクセスのために、ルート権限が必要です。

>>> import portio

# level を 3 に設定し、I/O ポートへのアクセスを許可します
>>> portio.iopl(3)   

# 0x2000 から 1 byte を読み出します
>>> portio.inb(0x2000)
254
  • 注意点:
    • inb や、outb に渡す port を間違えると、誤った機器に命令を送りつけてしまい、危険です。

3. PCI メモリ port へ接続する

$ sudo ipython

/dev/mem へのアクセスのために、ルート権限が必要です。

>>> import os
>>> import mmap

# メモリを読込専用で開きます
>>> f = os.open('/dev/mem', os.O_RDONLY)

# mmap でマッピングします
>>> m = mmap.mmap(f, 32, prot=mmap.PROT_READ, offset=0x90503000)

# 7 byte 目を読んでみます
>>> m.seek(0x07)
>>> m.read(1)
b'\x00'
  • 注意点:
    • mmap の offset に渡すアドレス値を間違えると、他のプロセスなどが使用中のメモリ領域へアクセスしてしまい、危険です。

pypci モジュール

  • 上記の手順だと、煩雑だし、アドレスを間違える危険性があるので、そこらへんをうまいことしてくれるモジュールを作りました。
  • PCI I/O port, PCI メモリ port の違いによらず、統一した API で操作できます。
  • pypci モジュール
    • インストール : pip install pypci

使い方

>>> import pypci

# PCI 設定情報を収集します。
# ベンダー ID、装置 ID を使って絞り込みます。
>>> board = pypci.lspci(vendor=0x1147, device=3214)

# port に関する情報は、Base Address Register に書き込まれています。
>>> board[0].bar
[BaseAddressRegister(type='mem', addr=2421170176, size=64),
 BaseAddressRegister(type='mem', addr=2421166080, size=64),
 BaseAddressRegister(type='mem', addr=2421174272, size=32)]

# BaseAddressRegister オブジェクトを使って通信します
>>> bar2 = board[0].bar[2]


# 読み込みの例
>>> pypci.read(bar2, 0x0c, 4)
b'\x00\x00\x00\x0c'

# アドレス範囲を超えると、エラーです
>>> pypci.read(bar2, 0x1d, 4)
BadAccessError: PCI addr space is 0x90503000-0x9050301f while tried to access 0x9050301d-0x90503020.


# 書き込みの例
>>> pypci.write(bar[2], 0x04, b'\x01')

>>> data = struct.pack('<I', 1234567)
>>> pypci.write(bar[2], 0x00, data)
13
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?