コグノスケ


link 未来から過去へ表示  link 過去から未来へ表示(*)

link もっと前
2021年7月9日 >>> 2021年8月5日
link もっと後

2021年7月9日

OpenOCDとHiFive UnleashedのSPI Flashその5 - UnleashedとOpenOCD消去の謎を追う

目次: OpenOCD

これまでに書き込み、消去の仕組みを調べました。その過程でどうしてHiFive UnleashedでSPI Flashの消去が正常に動作しないのかわかりました。アドレスの指定が間違っているからです。

SPI Flashの消去処理

// openocd/src/flash/nor/fespi.c

static int fespi_erase_sector(struct flash_bank *bank, int sector)
{

...

	retval = fespi_tx(bank, fespi_info->dev->erase_cmd);    //★ブロック64K消去コマンド(4バイトアドレスを期待)
	if (retval != ERROR_OK)
		return retval;
	sector = bank->sectors[sector].offset;
	retval = fespi_tx(bank, sector >> 16);    //★アドレス(3バイトしか送っていない)
	if (retval != ERROR_OK)
		return retval;
	retval = fespi_tx(bank, sector >> 8);
	if (retval != ERROR_OK)
		return retval;
	retval = fespi_tx(bank, sector);
	if (retval != ERROR_OK)
		return retval;

消去コマンドは0xdc(4BER64Kコマンド)で4バイトアドレスを期待していますが、今のOpenOCDの実装は3バイトアドレスを渡しています。これでは動作しません。最初に動作確認したログを覚えているでしょうか?改めて見直すと、

flash probe実行時の警告
$ riscv64-zephyr-elf-gdb

(gdb) set arch riscv:rv64

The target architecture is assumed to be riscv:rv64

(gdb) target remote :3333

Remote debugging using :3333

(gdb) monitor reset halt

JTAG tap: riscv.cpu tap/device found: 0x20000913 (mfg: 0x489 (SiFive Inc), part: 0x0000, ver: 0x2)

★★monitor xxxxはremote monitor(この場合OpenOCD)へのコマンドと解釈される

(gdb) monitor flash probe 0

Found flash device 'issi is25wp256d' (ID 0x0019709d)
device needs paging or 4-byte addresses - not implemented    ★★ん?なんだこれ
flash 'fespi' found at 0x20000000

OpenOCDが4バイトアドレスには対応していないよ、という警告を出していました。なるほど、やっと警告の意味がわかりました。

書き込みはどうして動くのか?

Unleashedの消去コマンドが動作しない理由はわかりましたが、まだいくつか不思議な点が残っています。

Unleashedで書き込みできるのはなぜ?
書き込みコマンドとして0x02(PPコマンド)を決め打ちしているためです。PPコマンドは3バイトアドレスを期待するので正常に動作します。ただし16MB以降には書き込みできないので、今の実装は十分とは言えません。
HiFive1が正常に書き換え、消去ができるのはなぜ?
搭載されているSPI Flashの型番が違うためです。HiFive1はISSI IS25LP032を搭載しています。SPI Flashのパラメータリストを見るとerase_cmd = 0xd8(BER64Kコマンド)になっていて、BER64Kコマンドは3バイトアドレスを期待するので正常に動作します。容量も小さいので3バイトアドレスで十分です。

比較しやすいようにSPI FlashのパラメータリストのうちHiFive1とHiFive Unleashedに関わるところだけ抜粋しておきます。

SPI Flashのパラメータを保持している配列の定義

// openocd/src/flash/nor/spi.c

const struct flash_device flash_devices[] = {
	/* name, read_cmd, qread_cmd, pprog_cmd, erase_cmd, chip_erase_cmd, device_id,
	 * pagesize, sectorsize, size_in_bytes */
	FLASH_ID("st m25p05",           0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00102020, 0x80,  0x8000,  0x10000),

...

	//★HiFive1が搭載しているFlash
	FLASH_ID("issi is25lp032",      0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0016609d, 0x100, 0x10000, 0x400000),

...

	//★HiFive Unleashedが搭載しているFlash
	FLASH_ID("issi is25wp256d",     0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000),

...

結論としてはOpenOCDの実装を変えないとHiFive UnleashedのSPI Flashの書き込み、消去は正常に行えないことがわかりました。手順では回避不可能です。

編集者:すずき(2023/09/24 09:18)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする




2021年8月2日

シンタックス・ハイライト

コードのキーワードハイライトに使っているhighlight.js(公式サイトへのリンク)を11.2.0にしました。導入したのは7年も前(2014年9月11日の日記参照)ですが、バージョンアップはスムーズにできました。

APIに変更があってinitHighlightingOnLoad() がdeprecatedになりました。代わりにhighlightAll() を呼べばOKです。ファイル名も微妙に変わっていました。スクリプトはhighlight.pack.jsからhighlight.min.jsに、CSSはvs.cssからvs.min.cssになっていました(Visual StudioスタイルのCSSを使う場合の設定、この他にもスタイルはたくさんあります)。

編集者:すずき(2021/08/05 13:02)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2021年8月3日

udevでPCIデバイスのパーミッションを設定する

目次: Linux

PCIデバイスを使った実験をする際にコンフィグ空間やメモリ空間を読み書きしたいときがあります。メモリ空間の読み書き程度ならば、わざわざPCIデバイスドライバを書かなくても /sys/bus/pci/devices/*/ にあるresourceNファイルにアクセスすれば良いです。

PCIデバイスはコンフィグ空間にBAR (Base Address Register) という32bitレジスタが6個あり、メモリ空間をPC側のアドレスのどこにマッピングするかを指定します。BARがそのままresourceNに対応しています。

最近は64bitアドレスでマッピングするデバイスも多いですが、その際は連続するBARを2つ使ってマッピング先のアドレスを指定します。実際に見たほうが早いと思うので、私の使っているマシンのグラフィックカードNVIDIA GeForce GT 1030を例にしましょう。

lspciでBARを確認
# lspci | grep VGA

08:00.0 VGA compatible controller: NVIDIA Corporation GP108 [GeForce GT 1030] (rev a1)

# lspci -s 08:00.0 -v

08:00.0 VGA compatible controller: NVIDIA Corporation GP108 [GeForce GT 1030] (rev a1) (prog-if 00 [VGA controller])
        Subsystem: Micro-Star International Co., Ltd. [MSI] GP108 [GeForce GT 1030]
        Flags: bus master, fast devsel, latency 0, IRQ 84, IOMMU group 14
        Memory at f6000000 (32-bit, non-prefetchable) [size=16M]    ★BAR0: resource0
        Memory at e0000000 (64-bit, prefetchable) [size=256M]       ★BAR1: resource1(64bitアドレス空間なのでBAR2も使われる)
        Memory at f0000000 (64-bit, prefetchable) [size=32M]        ★BAR3: resource3(64bitアドレス空間なのでBAR4も使われる)
        I/O ports at d000 [size=128]                                ★BAR5: resource5
        Expansion ROM at 000c0000 [virtual] [disabled] [size=128K]
        Capabilities: [60] Power Management version 3
        Capabilities: [68] MSI: Enable- Count=1/1 Maskable- 64bit+
        Capabilities: [78] Express Legacy Endpoint, MSI 00
        Capabilities: [100] Virtual Channel
        Capabilities: [128] Power Budgeting <?>
        Capabilities: [420] Advanced Error Reporting
        Capabilities: [600] Vendor Specific Information: ID=0001 Rev=1 Len=024 <?>
        Capabilities: [900] Secondary PCI Express
        Kernel driver in use: nvidia
        Kernel modules: nvidia

デバイスの位置(08:00.0)と、マッピングしているアドレスがBAR0, 1, 3, 5の4つ あることがわかります。/sys/bus/pci/devices経由でPCIデバイスのBAR1でマップされているメモリを読み出します。

GeForce GT 1030 BAR1の先頭をダンプ
# cd /sys/bus/pci/devices/0000\:08\:00.0/

# ma -k resource1 dd 0

00000000  ff000020 ff00082c  ff000020 ff00082c
00000010  ff3c0020 ff42082c  ff990020 ffa50027
00000020  ffa10020 ffa10027  ffa50020 ff990027
00000030  ff420020 ff3c0027  ff000020 ff000027
00000040  ff000020 ff000027  ff000020 ff000027
00000050  ff000020 ff000027  ff000020 ff000027
00000060  ff000020 ff000027  ff000020 ff000027
00000070  ff000020 ff000027  ff000020 ff000027
00000080  ff000020 ff000027  ff000020 ff000027
00000090  ff3c0020 ff420027  ffb90020 ffa50027
000000a0  ffa50020 ffb90027  ffa90020 ffa50027
000000b0  ff420020 ff3c0027  ff000020 ff000027
000000c0  ff000020 ff000027  ff000020 ff000027
000000d0  ff000020 ff000027  ff000020 ff000027
000000e0  ff000020 ff000027  ff000020 ff000027
000000f0  ff000020 ff000027  ff000020 ff000027
00000100

読み出しツールは何を使っても構いませんが、サイズがめっちゃでかい(256MB)ので「頭から読む系のツール(hexdumpやテキストエディタ)」は使わないほうが無難です。今回は拙作のmemaccess(GitHubへのリンク)を使いました。

ちなみにresourceNを読みだそうとすると怒られるときは、NVIDIAのドライバをロードしていないかチェックしてみてください。

NVIDIAのグラフィックドライバをロードしているとき、アンロードしたときの挙動
# ma -k resource0 dd 0

mmap: Invalid argument

# cat /proc/iomem

...
e0000000-fec2ffff : PCI Bus 0000:00
  e0000000-f1ffffff : PCI Bus 0000:08
    e0000000-efffffff : 0000:08:00.0
    f0000000-f1ffffff : 0000:08:00.0
  f6000000-f70fffff : PCI Bus 0000:08
    f6000000-f6ffffff : 0000:08:00.0
      f6000000-f6ffffff : nvidia    ★BAR0をnvidiaドライバが使用中なのでmmapできない
    f7080000-f7083fff : 0000:08:00.1
      f7080000-f7083fff : ICH HD audio
...

# rmmod nvidia_uvm nvidia_drm nvidia_modeset nvidia

# cat /proc/iomem

...
e0000000-fec2ffff : PCI Bus 0000:00
  e0000000-f1ffffff : PCI Bus 0000:08
    e0000000-efffffff : 0000:08:00.0
    f0000000-f1ffffff : 0000:08:00.0
  f6000000-f70fffff : PCI Bus 0000:08
    f6000000-f6ffffff : 0000:08:00.0    ★nvidiaドライバがアンロードされた
    f7080000-f7083fff : 0000:08:00.1
      f7080000-f7083fff : ICH HD audio
...

# ma -k resource0 dd 0

00000000  138000a1 00000000  00000000 bad00200
00000010  bad00200 bad00200  bad00200 bad00200
00000020  bad00200 bad00200  bad00200 bad00200
00000030  bad00200 bad00200  bad00200 bad00200
00000040  bad00200 bad00200  bad00200 bad00200
00000050  bad00200 bad00200  bad00200 bad00200
00000060  bad00200 bad00200  bad00200 bad00200
00000070  bad00200 bad00200  bad00200 bad00200
00000080  0000008f bad00200  bad00200 bad00200
00000090  bad00200 bad00200  bad00200 bad00200
000000a0  bad00200 bad00200  bad00200 bad00200
000000b0  bad00200 bad00200  bad00200 bad00200
000000c0  bad00200 bad00200  bad00200 bad00200
000000d0  bad00200 bad00200  bad00200 bad00200
000000e0  bad00200 bad00200  bad00200 bad00200
000000f0  bad00200 bad00200  bad00200 bad00200
00000100

ドライバが管理しているメモリを横から読み書きされたらたまったもんじゃないですから、この挙動は当然ですね。え?読み出しなら良いのでは?と思われるかもしれませんが、読み出しをトリガーに動作したり、読み出すと値が変化するレジスタなどは珍しくないので、勝手に読み出すのも実はダメなのです。

パーミッション面倒くさい

先ほど /sys/bus/pci/devices以下のファイルをls -lなどで見た方はお気づきかと思いますが、rootしか読めないようなパーミッションになっています。

resourceNのパーミッション設定
# cd /sys/bus/pci/devices/0000\:08\:00.0/

# ls -l resource*

-r--r--r-- 1 root root      4096  8月  2 22:08 resource
-rw------- 1 root root  16777216  8月  2 22:10 resource0
-rw------- 1 root root 268435456  8月  2 22:10 resource1
-rw------- 1 root root 268435456  8月  2 22:10 resource1_wc
-rw------- 1 root root  33554432  8月  2 22:10 resource3
-rw------- 1 root root  33554432  8月  2 22:10 resource3_wc
-rw------- 1 root root       128  8月  2 22:10 resource5

誰でもデバイスのメモリにアクセスできるのはマズいですから、セキュリティ上この設定は真っ当です。真っ当ですが、実験に使うときはいちいちsudoするのが面倒なのも事実です。手動でchmodやchownしてパーミッションを変えればsudo不要にできますが、いくつか欠点があります。

  • デバイスID 0000:08:00.0が常に同じとは限らない(カードの増設、撤去で変動する)
  • PCをリブートすると元に戻ってしまう

どこにいるかわからないデバイスを操作したいときは、udevの出番です。

udevでパーミッションを変える

前置きが長くなりましたが、やっと本題です。/etc/udev/rules.dに99-hogehoge.rulesのようなファイルを作ります。全てのPCIデバイスのパーミッションを全開にする必要はないので、ベンダーIDとデバイスIDでGeForce GT 1030だけ該当するようにフィルタリングしましょう。

ベンダーIDとデバイスIDの確認(lspciを使う方法)
# lspci -s 08:00.0

08:00.0 VGA compatible controller: NVIDIA Corporation GP108 [GeForce GT 1030] (rev a1)

# lspci -s 08:00.0 -n

08:00.0 0300: 10de:1d01 (rev a1)
              |    `--- Device ID
              `--- Vendor ID

他の条件をフィルタリングに使いたいときは、udevadm infoを使うと、vendorやdeviceも含んだ全ての属性を見ることができます。

ベンダーIDとデバイスIDの確認(udevadm infoを使う方法)
# udevadm info -a -p /sys/bus/pci/devices/0000:08:00.0 | less

...
  looking at device '/devices/pci0000:00/0000:00:03.1/0000:08:00.0':
    KERNEL=="0000:08:00.0"
    SUBSYSTEM=="pci"
    DRIVER==""
    ATTR{ari_enabled}=="0"
...
    ATTR{revision}=="0xa1"
    ATTR{subsystem_device}=="0x8c98"
    ATTR{subsystem_vendor}=="0x1462"
    ATTR{vendor}=="0x10de"    ★ベンダーID
...

IDが判明したらルールファイルを書きます。/sys/bus/pci/devices/* のディレクトリと配下のファイル全てにgroupとotherのRead/Writeパーミッションを付加します。%pは設定中のデバイスのパスが入る変数です。

udevのルール設定
SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{device}=="0x1d01", RUN+="/bin/chmod -R go+rw /sys%p"

注意点は「RUNはシェルじゃない」ことです。パスの補完、ワイルドカード、パイプ、リダイレクトなどは使えません。私は最初resource* と書いて「そんなファイルはない」と言われたり、/bin/chmodなのに /usr/bin/chmodと書いていて、何も実行されなくて悩みました(Ubuntuは /usr/bin/chmodだったりするので、さらにややこしいです)。

udevルールの反映
# udevadm trigger

# cd /sys/bus/pci/devices/0000\:08\:00.0/

# ls -l resource*

-r--rw-rw- 1 root root      4096  8月  2 23:10 resource
-rw-rw-rw- 1 root root  16777216  8月  2 23:10 resource0
-rw-rw-rw- 1 root root 268435456  8月  2 23:10 resource1
-rw-rw-rw- 1 root root 268435456  8月  2 23:10 resource1_wc
-rw-rw-rw- 1 root root  33554432  8月  2 23:10 resource3
-rw-rw-rw- 1 root root  33554432  8月  2 23:10 resource3_wc
-rw-rw-rw- 1 root root       128  8月  2 23:10 resource5

ルールファイルを書いたら設定を反映させると、resourceNファイルのパーミッションが変わっているはずです。変わっていない場合はおそらくルールの書き方が間違っているので、修正が必要です。

udevルールのデバッグ

むしろこちらが本題かもしれません。udevのRUNルールは「シェルじゃない」ので、普段シェル上で使っているコマンドをコピペしてもまず動かないです。間違っている場合は主に2パターンで、

  • フィルタリングのルールが間違っている
  • RUNの書き方が間違っている

前者に関してはRUNでログを出すとわかります。例えばRUN+="/usr/bin/logger AAAAAAAA" のようにすると、udevadm triggerを実行した後に /var/log/syslogにメッセージが出ます。

ログが出なければフィルタリングの条件を全部削って試してください。それでもログが出なければおそらくloggerのパスが間違っています。which loggerで出てくるパスとRUNに書いたパスが合っているか確認してください。特に /binと /usr/binは間違えやすいです。

後者に関してはRUNに書いたコマンドが失敗するとsyslogにエラーが記録されるはずですので、間違ってワイルドカードやパイプなどを書いていないかチェックしてみると良いです。

syslogに記録されるエラーの例
Aug  1 22:56:51 blackbird systemd-udevd[2775846]: 0000:08:00.0: Process '/bin/chmod -R go+rw /sys/devices/pci0000:00/0000:00:03.1/0000:08:00.0*' failed with exit code 1.

ログを見てもすぐにわからないような場合は、地道に「コマンド名だけにして実行されるか?」「引数を1つずつ足していって動くか?」を確認するのが一番良いです。

編集者:すずき(2023/09/24 13:37)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2021年7月9日 >>> 2021年8月5日
link もっと後

管理用メニュー

link 記事を新規作成

<2021>
<<<07>>>
----123
45678910
11121314151617
18192021222324
25262728293031

最近のコメント5件

  • link 24年6月17日
    すずきさん (06/23 00:12)
    「ありがとうございます。バルコニーではない...」
  • link 24年6月17日
    hdkさん (06/22 22:08)
    「GPSの最初の同期を取る時は見晴らしのい...」
  • link 24年5月16日
    すずきさん (05/21 11:41)
    「あー、確かにdpkg-reconfigu...」
  • link 24年5月16日
    hdkさん (05/21 08:55)
    「システム全体のlocale設定はDebi...」
  • link 24年5月17日
    すずきさん (05/20 13:16)
    「そうですねえ、普通はStandardなの...」

最近の記事3件

  • link 24年4月12日
    すずき (07/05 10:40)
    「[台湾東部沖地震に寄付] ささやかではありますが台湾東部沖地震に寄付しました。日本の赤十字社→台湾の赤十字(正式名称...」
  • link 24年4月16日
    すずき (07/05 10:40)
    「[Zephyr SDKのhosttoolsは移動してはいけない、その2 - インストール時のバイナリ書き換え] 目次: Zep...」
  • link 24年4月17日
    すずき (07/05 10:39)
    「[VSCodeとMarkdownとPlantUMLのローカルサーバー] 目次: LinuxVSCodeのPlantUML Ex...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 07/05 10:40