Vivado 2017.2でなぜかQSPIブートできない現象にハマった際のメモをここで供養する。
QSPIブートできないのはfsblのバグ(後述)で、おそらく2017.4では修正されているはず。
実際に参考にしたBOOT.binはxilinxが提供しているxilinx-zc702-v2017.2-final.bspというファイルのpre-buildに入っているもの。
BootROM
参考資料1(UG585)の6.3.2 BootROM ヘッダー
に記載。以下、表6-5を抜粋。
ヘッダーアドレス |
説明 |
道祖土コメント |
0x000 - 0x01F |
Interrupt Table for Execution-in-Place |
|
0x020 |
Width Detection |
0xAA995566固定 |
0x024 |
Image Identification |
'XLNX'固定 |
0x028 |
Encryption Status |
|
0x02C |
FSBL/ユーザー定義 |
|
0x030 |
Source Offset |
|
0x034 |
Length of Image |
|
0x038 |
0 |
|
0x03C |
Start of Execution |
|
0x040 |
Total Image Length |
|
0x044 |
0 |
実際は1 |
0x048 |
Header Checksum |
|
0x04C - 0x09F |
FSBL/ユーザー定義 (84バイト) |
|
0x0A0 - 0x89F |
Register Initialization (2048バイト) |
ALL 0xFFFF0000 |
0x8A0 - 0x8BF |
FSBL/ユーザー定義 |
ALL 0xFFFFFFFF |
0x8C0 - |
FSBLイメージまたはユーザーコード |
イメージヘッダー |
以下でファイルの内容を見てみる。
od -tx4 -v -Ax --endian little BOOT.BIN | less
先頭からBootROMヘッダーが始まっている。
000000 eafffffe eafffffe eafffffe eafffffe
000010 eafffffe eafffffe eafffffe eafffffe
000020 aa995566 584c4e58 00000000 01010000
000030 00001700 00018008 00000000 00000000
000040 00018008 00000001 fc164530 00000000
000050 00000000 00000000 00000000 00000000
000060 00000000 00000000 00000000 00000000
000070 00000000 00000000 00000000 00000000
000080 00000000 00000000 00000000 00000000
000090 00000000 00000000 000008c0 00000c80
イメージヘッダーテーブル
参考資料2(UG821)の付録A: Bootgenの使用
の表A-4を抜粋。
オフセット |
名前 |
注記 |
0x0 |
バージョン |
0x01020000 |
0x4 |
イメージヘッダー数 |
|
0x8 |
パーティションヘッダーのワードオフセット |
|
0xC |
最初のイメージヘッダーのワードオフセット |
|
0x10 |
ヘッダー認証のワードオフセット |
|
0x1C |
パディング |
64バイト境界までALL 0xFF |
0x000008A0からイメージヘッダーが始まると書いているが、実際のBOOT.binでは0x000008C0から始まっている。
BootROMヘッダーの説明(UG585)ではBootROMヘッダー自体のサイズが0x8C0と書かれているので誤記だと思う。
BootROMと同様に、odでBOOT.binを見てみる。
0008c0 01020000 00000003 00000320 00000240
0008d0 00000000 ffffffff ffffffff ffffffff
0008e0 ffffffff ffffffff ffffffff ffffffff
0008f0 ffffffff ffffffff ffffffff ffffffff
- イメージヘッダー数: 3
- パーティションヘッダーのワードオフセット: 0x320(バイトでは0xC80)
- 最初のイメージヘッダーのワードオフセット: 0x240(バイトでは0x900)
イメージヘッダー
イメージヘッダーテーブルのあとにはBootgenの作ったイメージヘッダーが並ぶ。
参考資料2(UG821)の付録A: Bootgenの使用
の表A-7を抜粋。
オフセット |
名前 |
0x0 |
次のイメージヘッダーのワードオフセット |
0x4 |
最初のパーティションヘッダーのワードオフセット |
0x8 |
0固定 |
0xC |
1固定(パーティション数) |
0x10 |
ここからファイル名 + 0x00000000 |
0x10 + ファイル名分 + 0x4 |
64バイト境界までALL 0xFF |
先程と同様にodの出力を見てみる。
000900 00000250 00000320 00000000 00000001
000910 7a796e71 5f667362 6c2e656c 66000000 # zynq_fsbl.elf
000920 00000000 ffffffff ffffffff ffffffff
000930 ffffffff ffffffff ffffffff ffffffff
000940 00000260 00000330 00000000 00000001
000950 646f776e 6c6f6164 2e626974 00000000 # download.bit
000960 00000000 ffffffff ffffffff ffffffff
000970 ffffffff ffffffff ffffffff ffffffff
000980 00000000 00000340 00000000 00000001
000990 752d626f 6f742e65 6c660000 00000000 # u-boot.elf
なので、このBOOT.binでは以下の位置にパーティションヘッダーがいる事がわかる。
- zynq_fsbl.elf: 0x320(バイトで0xC80)
- download.bit: 0x330(バイトで0xCC0)
- u-boot.elf: 0x340(バイトで0xD00)
参考資料2(UG821)の付録A: Bootgenの使用
の表A-5を抜粋。
オフセット |
名前 |
0x0 |
Partition Data Word Length (Encrypted) |
0x4 |
Extracted Data Word Length (Unencrypted) |
0x8 |
Total Partition Word Length |
0x0C |
Destination Load Address |
0x10 |
Destination Execution Address |
0x14 |
Data Word Offset in Image |
0x18 |
Attribute Bits |
0x1C |
Section Count |
0x20 |
Checksum Word Offset |
0x24 |
Image Header Word Offset |
0x28 |
Authentication Certification Word Offset |
0x2C |
unused (Must be 0x00000000) |
0x30 |
unused (Must be 0x00000000) |
0x34 |
unused (Must be 0x00000000) |
0x38 |
unused (Must be 0x00000000) |
0x3C |
Header Checksum |
例によって、odでBOOT.binを見てみる。
000c80 00006002 00006002 00006002 00000000 # 0x00 (zynq_fsbl.elf)
000c90 00000000 000005c0 00000010 00000001 # 0x10 (zynq_fsbl.elf)
000ca0 00000000 00000240 00000000 00000000 # 0x20 (zynq_fsbl.elf)
000cb0 00000000 00000000 00000000 fffed7e8 # 0x30 (zynq_fsbl.elf)
000cc0 000f6ec0 000f6ec0 000f6ec0 00000000 # 0x00 (download.bit)
000cd0 00000000 000065d0 00000020 00000001 # 0x10 (download.bit)
000ce0 00000000 00000250 00000000 00000000 # 0x20 (download.bit)
000cf0 00000000 00000000 00000000 ffd14b7e # 0x30 (download.bit)
000d00 00019090 00019090 00019090 00400000 # 0x00 (u-boot.elf)
000d10 00400000 000fd490 00000010 00000001 # 0x10 (u-boot.elf)
000d20 00000000 00000260 00000000 00000000 # 0x20 (u-boot.elf)
000d30 00000000 00000000 00000000 ff6b774e # 0x30 (u-boot.elf)
特に変なところもなく、以下のことが分かる。
- u-bootだけ0x0C/0x10のロード/実行アドレスが0x00400000
- 0x18のAttributeは、bitファイルだけPL(0x00000020)、その他はPS(0x00000010)
(参考)QSPIブートできない現象のデバッグ
s25fl256s1というFlashメモリで起動しようとすると、以下の表示になる。(fsblでシンボルFSBL_DEBUG_INFO
を有効にしてシリアル出力させる)
Xilinx First Stage Boot Loader
Release 2017.1 Jul 7 2017-16:40:46
Devcfg driver initialized
Silicon Version 3.1
Boot mode is QSPI
Single Flash Information
FlashID=0x1 0x2 0x19
SPANSION 256M Bits
QSPI is in single flash connection
QSPI Init Done
Flash Base Address: 0xFC000000
Reboot status register: 0x60400000
Multiboot Register: 0x0000C000
Image Start Address: 0x00000000
Partition Header Offset:0x00000880 <==== 0xC80のはず
Partition Count: 14
Invalid Partition Count
Partition Header Load Failed
FSBL Status = 0xA00E
...(以下Fallback bootの結果)
u-bootやlinuxでQSPIの中身を読んでみると正常に書き込めている。
fsblでは、polled transferをしているようなので、xqspips_flash_polled_example.c(サンプルデザイン)を実行してみる。
printf()爆弾を仕込んだxqspips_flash_polled_example.cで動作確認したところ、
#define FAST_READ_CMD 0x0B
#define DUAL_READ_CMD 0x3B
#define QUAD_READ_CMD 0x6B
のうち、QUAD_READ_CMDがNGであることがわかった。
fsbl内で同様の操作をしている箇所は、qspi.cのFlashRead()であるので、
リードコマンドになるであろう、WriteBuffer[COMMAND_OFFSET]をモニタしてみたところ、
0x04とかいう謎の値が入っていた。
これを以下のように、FAST_READ_CMDにハードコードすることで読み出しできるようになった。
diff -r e93b7f0ac8b0 xsdk/fsbl/src/qspi.c
--- a/xsdk/fsbl/src/qspi.c Fri Jul 07 16:23:45 2017 +0900
+++ b/xsdk/fsbl/src/qspi.c Mon Jul 10 09:11:51 2017 +0900
@@ -91,7 +91,9 @@
* The following constants define the commands which may be sent to the FLASH
* device.
*/
-#define QUAD_READ_CMD 0x6B
+#define FAST_READ_CMD 0x0B // s25fl256s1 OK
+#define DUAL_READ_CMD 0x3B // s25fl256s1 OK
+#define QUAD_READ_CMD 0x6B // s25fl256s1 NG
#define READ_ID_CMD 0x9F
#define WRITE_ENABLE_CMD 0x06
@@ -441,12 +443,8 @@
* Setup the write command with the specified address and data for the
* FLASH
*/
- u32 LqspiCrReg;
- u8 ReadCommand;
-
- LqspiCrReg = XQspiPs_GetLqspiConfigReg(QspiInstancePtr);
- ReadCommand = (u8) (LqspiCrReg & XQSPIPS_LQSPI_CR_INST_MASK);
- WriteBuffer[COMMAND_OFFSET] = ReadCommand;
+ /* XQspiPs_GetLqspiConfigReg()で得られる値がおかしい */
+ WriteBuffer[COMMAND_OFFSET] = FAST_READ_CMD; // for s25fl256s1
WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16);
WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8);
WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF);